Guides

Interactive Styles

Interactive styles let you define CSS that applies only when an element is in a specific state -- hovered, focused, active, or toggled by JavaScript. They work like CSS pseudo-classes and conditional selectors, but you configure them visually.


Adding an Interactive Style

  1. Select an element on the canvas or in the Structure tree.

  2. In the Properties panel, scroll down to the Interactive Styles section.

  3. Click + to add a new interactive style rule.

  4. Choose a selector from the common options (:hover, :focus, :active) or type a custom one.

  5. Add CSS properties that should apply when that state is active.

  6. The canvas shows a live preview when you hover or interact with the element.

Common Selectors

The most frequently used interactive styles:

Hover

Make a button change color when the mouse moves over it:

  1. Select the button element.

  2. Add an interactive style with postfix :hover.

  3. Set backgroundColor to a darker shade (e.g., var(--primary-dark)).

Focus

Add a visible focus ring for keyboard navigation:

  1. Select the input or link element.

  2. Add an interactive style with postfix :focus.

  3. Set outline to 2px solid var(--primary) and outlineOffset to 2px.

Active

Give click feedback:

  1. Select the element.

  2. Add an interactive style with postfix :active.

  3. Set transform to scale(0.98) for a subtle press effect.

How Selectors Work

Each interactive style rule has two parts that build a CSS selector:

Part

Position

What It Does

postfix

After the element's class

Appends to the element (e.g., :hover, .is-open)

prefix

Before the element's class

Prepends an ancestor context (e.g., .dark )

The generated CSS selector follows the pattern: {prefix}.element-class{postfix}

Selector Reference

Use Case

prefix

postfix

Generated Selector

Hover

""

":hover"

.el:hover

Focus

""

":focus"

.el:focus

Active

""

":active"

.el:active

Focus-visible

""

":focus-visible"

.el:focus-visible

Self has class

""

".is-open"

.el.is-open

Target child

""

".is-open [data-el='menu']"

.el.is-open [data-el='menu']

Ancestor context

".dark "

""

.dark .el

Ancestor + hover

".dark "

":hover"

.dark .el:hover

Sibling context

""

":hover + .sibling"

.el:hover + .sibling

Important: When using a prefix to target an ancestor, include a trailing space (e.g., ".dark " not ".dark"). Without the space, the selector becomes .dark.el (same element has both classes) instead of .dark .el (ancestor has .dark).

JavaScript-Driven States

Interactive styles are not limited to CSS pseudo-classes. You can use them with classes toggled by JavaScript.

Pattern: Toggle a Class

  1. In your component's JS file, add or remove a class on the component root element:

``javascript el.classList.toggle('is-open'); ``

  1. In the editor, add an interactive style with postfix ".is-open" on the element.

  2. Set the styles that should apply when the class is present.

Pattern: Target a Child Element

You can make a child element respond to a class on the parent:

  1. Add a data-el attribute to the child element (e.g., data-el="menu").

  2. On the parent element, add an interactive style with postfix ".is-open [data-el='menu']".

  3. Set styles like display: "block" or opacity: "1" for the visible state.

This way, when JavaScript adds .is-open to the parent, the child element becomes visible.

Example: Dropdown Menu

Here is a complete dropdown pattern combining interactive styles with JavaScript:

Step 1: Build the Structure

Create a component with this structure:

  • Root <div> -- the dropdown container

  • <button> with data-el="trigger" -- the toggle button

  • <div> with data-el="menu" -- the dropdown content

Step 2: Style the Menu (Hidden by Default)

On the menu element ([data-el="menu"]), set base styles:

  • display: "none"

  • position: "absolute"

  • top: "100%"

  • backgroundColor: "var(--surface)"

  • boxShadow: "0 4px 12px rgba(0,0,0,0.15)"

  • borderRadius: "8px"

Step 3: Add Interactive Style for Open State

On the root element (the dropdown container), add an interactive style:

  • postfix: ".is-open [data-el='menu']"

  • style: { "display": "block" }

This makes the menu visible when the root has the .is-open class.

Step 4: Add Hover Style on Trigger

On the button element, add an interactive style:

  • postfix: ":hover"

  • style: { "backgroundColor": "var(--surface)" }

Step 5: Write the JavaScript

Create the component's JS file:

const trigger = el.querySelector('[data-el="trigger"]');

trigger?.addEventListener('click', () => {
  el.classList.toggle('is-open');
});

// Close when clicking outside
document.addEventListener('click', (e) => {
  if (!el.contains(e.target)) {
    el.classList.remove('is-open');
  }
});

Dark Mode with Interactive Styles

If your project supports a dark mode class on the <body> or a wrapper element, use prefix selectors:

  1. On any element, add an interactive style with prefix ".dark " (note the trailing space).

  2. Set dark-mode colors: backgroundColor: "var(--dark-surface)", color: "var(--dark-text)".

The styles apply only when an ancestor element has the .dark class.

Responsive Interactive Styles

Interactive styles support the same responsive breakpoints as regular styles:

  1. Add an interactive style rule.

  2. Set different values for base, tablet, and mobile within the style object.

For example, you might want a hover effect on desktop but not on mobile (where hover is unreliable):

  • base: { "backgroundColor": "var(--primary-dark)" }

  • mobile: { "backgroundColor": "var(--primary)" } (same as non-hover, effectively disabling it)


Under the Hood

Interactive Styles JSON Format

Interactive styles are stored as an array of rule objects on the node:

{
  "type": "node",
  "tag": "button",
  "style": {
    "base": {
      "padding": "12px 24px",
      "backgroundColor": "var(--primary)",
      "color": "var(--on-primary)",
      "borderRadius": "6px",
      "border": "none",
      "cursor": "pointer",
      "transition": "all 0.2s ease"
    }
  },
  "interactiveStyles": [
    {
      "postfix": ":hover",
      "style": {
        "base": {
          "backgroundColor": "var(--primary-dark)",
          "transform": "translateY(-1px)"
        }
      }
    },
    {
      "postfix": ":active",
      "style": {
        "base": {
          "transform": "translateY(0)"
        }
      }
    },
    {
      "postfix": ":focus-visible",
      "style": {
        "base": {
          "outline": "2px solid var(--primary)",
          "outlineOffset": "2px"
        }
      }
    }
  ]
}

Rule Object Properties

Property

Type

Required

Description

name

string

No

Friendly label for the rule (e.g., "onHover")

prefix

string

No

Selector text before element class

postfix

string

No

Selector text after element class

style

object

Yes

Responsive style object (base, tablet, mobile)

previewProp

string

No

Boolean prop name that toggles preview in editor

Multiple Rules Example

A navigation link with hover, active, and "current page" states:

"interactiveStyles": [
  {
    "name": "hover",
    "postfix": ":hover",
    "style": {
      "base": { "color": "var(--primary)", "textDecoration": "underline" }
    }
  },
  {
    "name": "active page",
    "postfix": ".is-active",
    "style": {
      "base": {
        "color": "var(--primary)",
        "fontWeight": "600",
        "borderBottom": "2px solid var(--primary)"
      }
    }
  },
  {
    "name": "dark mode",
    "prefix": ".dark ",
    "postfix": "",
    "style": {
      "base": { "color": "var(--dark-text)" }
    }
  }
]

Next Steps

  • JavaScript -- Write the JS that toggles classes for interactive styles.

  • Styling -- Master base styles and responsive design.

  • Building Components -- Package interactive patterns as reusable components.

Building the future of digital experiences, one website at a time

© 2026 Company. All rights reserved.