Styling contracts
Headless toggle styling is driven by primitive state attributes. Build your surface around those hooks instead of depending on undocumented DOM.
| Selector | Applied on | Purpose |
|---|---|---|
[data-slot="toggle"] | Primitive button | Stable base selector for the toggle item. |
[data-state="on"], [data-state="off"] | Primitive button | Pressed and unpressed state styling. |
[data-disabled] | Primitive button + group | Disabled visuals on the item and the shared surface. |
[data-focused], [data-focus-visible] | Primitive button | Focus rings and keyboard-only emphasis. |
[data-slot="toggle-group"] | Group host | Stable selector for grouped shells. |
[data-selection-mode], [data-orientation] | Group host | Layout variants and grouped state hints. |
State selectors
These two snippets are the minimum contract most shells build on.
Toggle item selectors
css
button[tngToggle][data-slot="toggle"] {
background: #ffffff;
border: 1px solid #c6d4e1;
color: #1e293b;
}
button[tngToggle][data-state="on"] {
background: #2563eb;
border-color: #2563eb;
color: #ffffff;
}
button[tngToggle][data-disabled] {
cursor: not-allowed;
opacity: 0.55;
}
button[tngToggle]:focus-visible {
outline: 2px solid rgba(37, 99, 235, 0.28);
outline-offset: 2px;
}
Group shell selectors
css
[tngToggleGroup][data-slot="toggle-group"] {
display: inline-flex;
flex-wrap: wrap;
gap: 0.55rem;
padding: 0.55rem;
border: 1px solid #dbe4ee;
border-radius: 1rem;
background: #f8fafc;
}
[tngToggleGroup][data-disabled] {
opacity: 0.6;
}
Example shells
The same formatting contract can sit inside a plain CSS shell or a Tailwind utility shell.
Formatting shell (Plain-CSS)
Formatting tools
Make active states obvious without losing native button semantics.
Active: bold, code
Formatting shell (Tailwind CSS)
Formatting tools
Use state attributes directly while the shell is expressed with utilities.
Active: mentions