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
- Automatic
aria-describedbyon the trigger element role="tooltip"for screen readers- Focus stays on trigger (tooltips never steal focus)
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
## 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 focus, hide on blur - '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
| Property | Description |
| --- | --- |
| `--hy-tooltip-foreground` | Tooltip text color (inverted: uses surface-base) **Default:** `var(--hy-background-surface-base)` |
| `--hy-tooltip-background` | Tooltip background color (inverted: uses surface-inverse) **Default:** `var(--hy-background-surface-inverse)` |
| `--hy-tooltip-padding-block` | Block padding (default: var(--hy-padding-overlay-floating-sm-block)) |
| `--hy-tooltip-padding-inline` | Inline padding (default: var(--hy-padding-overlay-floating-sm-inline)) |
| `--hy-tooltip-radius` | Border radius (default: var(--hy-radius-overlay-floating-sm)) |
| `--hy-tooltip-max-width` | Maximum width (default: surface-width-sm) |
| `--hy-tooltip-ornament` | Arrow indicator size (default: var(--hy-ornament-bullet)) |
| `--hy-tooltip-safe-zone` | Safe hover zone around tooltip, set dynamically via JS (default: 12px) |
| `--hy-tooltip-shadow` | Box shadow for the tooltip |
| `--hy-tooltip-font-family` | Font family override for tooltip text |
| `--hy-tooltip-enter-duration` | Transition duration for the show and hide animation |
| `--hy-tooltip-enter-easing` | Transition easing for the show and hide animation |
## Methods
### show()
Shows the tooltip programmatically.
### hide()
Hides the tooltip programmatically.