Styling contract
Empty wrapper components expose the same public slot hooks as the primitives. Style through those hooks first, and move to headless or ownable when you need to own the full shell.
Wrapper slot hooks
Style the same selectors for both headless primitives and wrapper components: empty, empty-icon, empty-title, empty-description, and empty-actions.
Recommended CSS contract
css
[data-slot="empty"] {
border: 1px dashed var(--tng-semantic-border-strong);
border-radius: 1rem;
display: grid;
gap: 0.75rem;
justify-items: center;
padding: 1.5rem;
}
[data-slot="empty"][data-align="start"] {
justify-items: start;
text-align: left;
}
[data-slot="empty-icon"] {
color: var(--tng-semantic-foreground-muted);
font-size: 1.75rem;
}
[data-slot="empty-actions"] {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
Default shell
The wrapper already provides a dashed surface, text alignment, and basic part spacing. Treat those defaults as a baseline shell rather than styling against private wrapper internals.
Owner guidance
- Use wrapper styling when the built-in surface and
alignoption are close to what your product needs. - Use headless empty when you need a fully custom shell, illustration region, or semantic container.
- Use the ownable install when you want the wrapper model but need to edit the generated shell locally.