Styling contract
Headless Badge generates the bubble node for you, but styling still belongs to your host class and the stable hooks on the generated .tng-badge element.
Generated node hooks
| Hook | Where it appears | Use it for |
|---|---|---|
.tng-badge | Generated badge node | Base badge visuals. |
data-slot="badge" | Generated badge node | Stable attribute selector for the bubble. |
data-position, data-placement | Generated badge node | Placement-specific transforms. |
data-size, data-tone, data-variant | Generated badge node | Theme and size contracts. |
data-dot, data-disabled | Generated badge node | Dot mode and disabled-state styling. |
.tng-badge-host, data-tng-badge-host | Host element | Parent-level layout and placement overrides. |
CSS starter
Build your shell on the host, then style the generated bubble beneath it.
badge-host.css
css
.notification-host {
align-items: center;
appearance: none;
background: var(--tng-semantic-background-surface);
border: 1px solid var(--tng-semantic-border-strong);
border-radius: 0.65rem;
display: inline-flex;
min-height: 2.5rem;
padding-inline: 1rem;
}
.notification-host .tng-badge {
background: var(--tng-badge-bg, #dc2626);
color: var(--tng-badge-fg, #ffffff);
}
Host guidance
The directive will add position: relative to the host when no inline position is present, so badge placement has a stable anchor. Prefer your own host class for anything more specific.
badge-placement.css
css
.notification-host {
position: relative;
}
.notification-host[data-tng-badge-host] .tng-badge[data-position="bottom-start"] {
transform: translate(-50%, 50%);
}