HyTooltip
Usage examples on this page are written for Lit / plain HTML (
<hy-tooltip>). The same component ships asHyTooltipin@whitespaceux/harmony-react(native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.
A lightweight tooltip component that displays contextual information when hovering or focusing on an element.
Trigger Patterns
Slotted trigger (preferred for client-side apps): The trigger element is passed via the trigger slot, ensuring ARIA relationships work correctly across shadow DOM boundaries.
for attribute (fallback for SSR frameworks): For SSR frameworks like Next.js, Nuxt, or SvelteKit, use the for attribute to reference a trigger element by ID. This avoids hydration timing issues with the slotchange event.
Key Features
- Automatic positioning with Floating UI
- Configurable show/hide delays
- Hover, focus, or combined triggers
- Dismissible, hoverable, and persistent
- Full keyboard support (Escape to dismiss)
- SSR-compatible via
forattribute fallback
Accessibility: built in
- Automatic
aria-describedbyon the trigger element role="tooltip"for screen readers- Focus stays on trigger (tooltips never steal focus)
Accessibility: your part
- Put a focusable control in the
triggerslot, such ashy-icon-button, never a bare span; a hint on a disabled control needs a trigger that can still take focus. - Never let the tooltip be a control's only accessible name; give the control its own
labeloraria-label.
When to use
- Naming an icon-only control.
- A short hint about a control that people may want but do not need.
Do
- Keep it to a few words or one short sentence.
When not to use
- Text people must read to go on: show it inline on the page.
- Content with links, buttons or fields, or longer than one short sentence:
hy-popover. - A control whose visible label already says the same thing: no tooltip.
- A problem with a field's value: the field's own
error-messageorwarning-message. - Brief confirmation such as saved or copied:
hy-toast.
Examples
Basic Usage (Slotted Trigger)
<hy-tooltip>
<button slot="trigger">Save</button>
Save your changes
</hy-tooltip>SSR Framework Usage (for attribute)
<button id="save-btn">Save</button> <hy-tooltip for="save-btn">Save your changes</hy-tooltip>With Placement
<hy-tooltip placement="bottom">
<button slot="trigger">?</button>
Click for help
</hy-tooltip>Hover Only
<hy-tooltip trigger="hover">
<span slot="trigger" tabindex="0">API</span>
Application Programming Interface
</hy-tooltip>Custom Delay
<hy-tooltip delay="500">
<button slot="trigger">Delete</button>
This cannot be undone
</hy-tooltip>Note: show / hide are dispatched with bubbles: false. A tooltip's visibility is a purely local concern (no parent-coordination protocol like menubar↔menu-item), and a bubbling composed hide would collide with an ancestor overlay's same-named handler — e.g. a tooltip inside an hy-dialog would trip the dialog's onhide and close the modal. Listen directly on the <hy-tooltip> element (onshow / onhide) — target-phase delivery is unaffected. Matches the React mirror, whose onShow / onHide are callbacks that never bubble.
API
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
placement | placement | 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end' | 'top' | Where to place the tooltip relative to the trigger. Uses Floating UI with automatic fallback when there isn't enough space. |
distance | distance | number | 6 | Distance between the tooltip and its trigger element in pixels. |
trigger | trigger | 'hover' | 'focus' | 'hover focus' | 'hover focus' | How the tooltip is triggered. - 'hover': Show on mouseenter, hide on mouseleave - 'focus': Show on keyboard focus (:focus-visible), hide on blur — the focus a click gives the trigger, or focus handed back to it after a pointer pick in a menu, does not open it - 'hover focus': Show on either, requires both to be removed to hide |
delay | delay | number | 200 | Delay before showing the tooltip in milliseconds. |
hideDelay | hide-delay | number | 100 | Delay before hiding the tooltip in milliseconds. |
arrow | arrow | boolean | true | Whether to show the arrow indicator. |
open | open | boolean | false | Controls the open state of the tooltip. |
disabled | disabled | boolean | false | Disables the tooltip entirely. When disabled, the tooltip will not show on any trigger. |
for | for | string | undefined | — | ID of the trigger element. Use this as a fallback when the slotted trigger pattern isn't available (e.g., in SSR frameworks where slot forwarding may not work). |
Events
| Event | Detail | Description |
|---|---|---|
show | — | Fired after the tooltip opens (does NOT bubble). Detail: { source: 'hover' | 'focus' | 'programmatic' } |
hide | — | Fired after the tooltip closes (does NOT bubble). Detail: { source: 'hover' | 'focus' | 'escape-key' | 'programmatic' } |
Slots
| Slot | Description |
|---|---|
trigger | The element that triggers the tooltip (required) |
default | The tooltip content |
CSS Parts
| Part | Description |
|---|---|
body | The tooltip content wrapper |
arrow | The arrow indicator element |
CSS Custom Properties
The documented hooks. Every override hook the component reads — one per token it paints — is listed in @whitespaceux/harmony/theme-api.json, and @whitespaceux/harmony/component-bindings.json (the Harmony MCP get-bindings tool) says which part and state each one paints.
| Property | Default | Description |
|---|---|---|
--hy-tooltip-background-surface-base | var(--hy-background-surface-base) | Tooltip text color (inverted: uses surface-base) |
--hy-tooltip-background-surface-inverse | var(--hy-background-surface-inverse) | Tooltip background color (inverted: uses surface-inverse) |
--hy-tooltip-padding-overlay-floating-sm-block | var(--hy-padding-overlay-floating-sm-block) | Block padding |
--hy-tooltip-padding-overlay-floating-sm-inline | var(--hy-padding-overlay-floating-sm-inline) | Inline padding |
--hy-tooltip-radius-overlay-floating-sm | var(--hy-radius-overlay-floating-sm) | Border radius |
--hy-tooltip-surface-width-sm | var(--hy-surface-width-sm) | Maximum width (default: surface-width-sm) |
--hy-tooltip-ornament-bullet | var(--hy-ornament-bullet) | Arrow indicator size |
--hy-tooltip-safe-zone | — | Safe hover zone around tooltip, set dynamically via JS (default: 12px) |
--hy-tooltip-shadow-elevation-2 | var(--hy-shadow-elevation-2) | Box shadow for the tooltip |
--hy-tooltip-body-sm-font-family | var(--hy-body-sm-font-family) | Font family override for tooltip text |
--hy-tooltip-motion-transition-enter-duration | var(--hy-motion-transition-enter-duration) | Transition duration for the show animation |
--hy-tooltip-motion-transition-enter-easing | var(--hy-motion-transition-enter-easing) | Transition easing for the show animation |
--hy-tooltip-motion-transition-exit-duration | var(--hy-motion-transition-exit-duration) | Transition duration for the hide animation |
--hy-tooltip-motion-transition-exit-easing | var(--hy-motion-transition-exit-easing) | Transition easing for the hide animation |
Methods
show()
Shows the tooltip programmatically.
hide()
Hides the tooltip programmatically.