Styling contract
Headless tabs expose stable slot and state attributes without forcing any wrapper shell or default trigger markup.
Stable hooks
| Hook | Values | Where |
|---|---|---|
data-slot | tabs, tab-list, tab, tab-panel | Root and all registered parts. |
data-selected, data-focused, data-disabled | true | false | Tab triggers. |
data-active | true | false | Panels. |
data-orientation, data-activation | orientation / activation mode | Root. |
CSS starter
tabs.primitive.css
css
[data-slot="tabs"] {
display: grid;
gap: 0.75rem;
}
[data-slot="tab-list"] {
display: flex;
gap: 0.5rem;
}
[data-slot="tab"][data-selected="true"] {
background: var(--tng-semantic-background-surface);
}
[data-slot="tab-panel"][hidden] {
display: none !important;
}
Owner guidance
Prefer styling the explicit slot hooks instead of raw element names. That keeps your tabs contract resilient if you later swap a button trigger for another authored host.