Styling contract
Headless dialog publishes slot and state hooks for the modal root, backdrop, panel, and action controls. Style those hooks directly instead of depending on descendant selectors or wrapper classes.
Slot and state hooks
[data-slot="dialog"]mirrorsdata-open,data-state,data-size, anddata-disabled.[data-slot="dialog-backdrop"]is the fixed overlay layer that owns spacing and backdrop visuals.[data-slot="dialog-panel"]is the focus target with size and open-state attributes.[data-slot="dialog-trigger"],[data-slot="dialog-close"],[data-slot="dialog-title"],[data-slot="dialog-description"], and[data-slot="dialog-actions"]provide stable hooks for shell polish.
CSS starter
headless-dialog.css
css
[data-slot="dialog-backdrop"] {
align-items: center;
background: rgb(2 6 23 / 58%);
display: grid;
inset: 0;
padding: 1rem;
position: fixed;
}
[data-slot="dialog-panel"] {
background: var(--tng-semantic-background-surface);
border: 1px solid var(--tng-semantic-border-subtle);
border-radius: 1rem;
box-shadow: 0 24px 56px rgb(2 6 23 / 28%);
display: grid;
gap: 0.85rem;
inline-size: min(100%, 34rem);
padding: 1rem;
}
[data-slot="dialog-panel"][data-size="lg"] {
inline-size: min(100%, 42rem);
}
[data-slot="dialog-actions"] {
display: flex;
flex-wrap: wrap;
gap: 0.625rem;
justify-content: flex-end;
}
[data-slot="dialog-close"],
[data-slot="dialog-trigger"] {
border-radius: 0.75rem;
}
Owner guidance
- Keep the backdrop and panel styling local to the dialog shell so modal contrast stays consistent.
- Size the panel from the slot hooks instead of hard-coding widths on inner content wrappers.
- Use
data-sizeas the shared contract between layout tokens and product-specific variants. - Prefer styling focus states on your trigger and action buttons directly; the primitive only manages the behavior.