Tooltip
The tooltip text lives in a data attribute and is drawn by a pseudo-element, so there is no script, nothing to position at runtime, and nothing left behind in the DOM. It appears on hover and on keyboard focus, which the :focus-within half of the rule takes care of.
Basic tooltip
stack({ direction: 'row', gap: 'md' },
tooltip({ content: 'Copy to clipboard' },
iconButton({
label: 'Copy',
variant: 'soft',
color: 'neutral',
icon: icon('copy'),
}),
),
tooltip({ content: 'Rebuild the site' },
button({ variant: 'outline', color: 'neutral' }, 'Rebuild'),
),
)Placement
Above by default, below when there is no room above.
stack({ direction: 'row', gap: 'lg' },
tooltip({ content: 'Above the trigger' },
button({ variant: 'soft', color: 'neutral' }, 'Top'),
),
tooltip({ content: 'Below the trigger', placement: 'bottom' },
button({ variant: 'soft', color: 'neutral' }, 'Bottom'),
),
)Accessible names
The tooltip text is decoration — it is drawn from CSS content, which screen readers do not reliably announce. The control inside still needs its own accessible name, which is what iconButton()’s label provides. When the tooltip says something the control’s name does not, pass label: true to repeat it in a visually hidden span.
stack({ direction: 'row', gap: 'lg' },
tooltip({ content: 'Deploys to production immediately', label: true },
button({ color: 'danger' }, 'Deploy'),
),
)On text
A tooltip wraps inline content as happily as it wraps a button.
The build writes to dist/ and nothing else.
text(
'The build writes to ',
tooltip({ content: 'Configurable with outDir' }, code('dist/')),
' and nothing else.',
)When not to use one
Tooltips do not appear on touch, and they vanish the moment the pointer leaves. Anything a reader must have — an error message, an explanation of a required field — belongs in help text on the field itself, not in a tooltip.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
content | string | — | The hint text. |
placement | 'top' | 'bottom' | 'top' | Which side of the trigger it appears on. |
label | boolean | false | Also expose the text to screen readers, in a hidden span. |