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
Select an element on the canvas or in the Structure tree.
In the Properties panel, scroll down to the Interactive Styles section.
Click + to add a new interactive style rule.
Choose a selector from the common options (
:hover,:focus,:active) or type a custom one.Add CSS properties that should apply when that state is active.
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:
Select the button element.
Add an interactive style with postfix
:hover.Set
backgroundColorto a darker shade (e.g.,var(--primary-dark)).
Focus
Add a visible focus ring for keyboard navigation:
Select the input or link element.
Add an interactive style with postfix
:focus.Set
outlineto2px solid var(--primary)andoutlineOffsetto2px.
Active
Give click feedback:
Select the element.
Add an interactive style with postfix
:active.Set
transformtoscale(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., |
prefix | Before the element's class | Prepends an ancestor context (e.g., |
The generated CSS selector follows the pattern: {prefix}.element-class{postfix}
Selector Reference
Use Case | prefix | postfix | Generated Selector |
|---|---|---|---|
Hover |
|
|
|
Focus |
|
|
|
Active |
|
|
|
Focus-visible |
|
|
|
Self has class |
|
|
|
Target child |
|
|
|
Ancestor context |
|
|
|
Ancestor + hover |
|
|
|
Sibling context |
|
|
|
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
In your component's JS file, add or remove a class on the component root element:
``javascript
el.classList.toggle('is-open');
``
In the editor, add an interactive style with postfix
".is-open"on the element.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:
Add a
data-elattribute to the child element (e.g.,data-el="menu").On the parent element, add an interactive style with postfix
".is-open [data-el='menu']".Set styles like
display: "block"oropacity: "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>withdata-el="trigger"-- the toggle button<div>withdata-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:
On any element, add an interactive style with prefix
".dark "(note the trailing space).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:
Add an interactive style rule.
Set different values for
base,tablet, andmobilewithin 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 |
|---|---|---|---|
| string | No | Friendly label for the rule (e.g., |
| string | No | Selector text before element class |
| string | No | Selector text after element class |
| object | Yes | Responsive style object ( |
| 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.