Tooltip
The <x-wirekit::tooltip> component shows contextual information on hover, focus, and long-press (touch). Positioned via Floating UI with automatic flip/shift.
Tooltips should never be the only source of critical information. For essential details, use visible labels or hint text. On touch devices, tooltips are triggered by long-press (500ms).
Usage
Text Tooltip
Rich Content Tooltip
Width & Layout
Plain-text tooltips (text prop) auto-size to their content with a max-width for readability. Rich tooltips (slot content) size to their content — add explicit widths if needed:
<x-wirekit::tooltip>
<x-slot:content>
<div class="w-64">Wider tooltip with more detailed content.</div>
</x-slot:content>
<x-wirekit::button intent="neutral" surface="ghost" size="sm">Details</x-wirekit::button>
</x-wirekit::tooltip>
Placement
Control where the tooltip appears relative to its trigger:
Available placements: top, top-start, top-end, bottom, bottom-start, bottom-end, left, left-start, left-end, right, right-start, right-end.
Styling Variants
The tooltip's surface, text color, border radius, and opacity all derive from CSS variables — override them per-tooltip via inline style (scopes to the trigger wrapper) or globally via theme :root. Hover each button below to see a different style applied without changing the component itself.
Per-tooltip overrides win because the inline style cascades onto the hover-trigger wrapper, which the tooltip panel reads via var(--color-wk-tooltip-*). For an app-wide tooltip palette change, set the same tokens on :root {} in app.css instead of per-instance.
Custom Delays
Control how quickly tooltips appear and disappear. In the preview below, the left button shows instantly and hides slowly; the right button waits before showing and hides quickly:
Trigger Behavior
| Device | Show Trigger | Hide Trigger | Auto-Dismiss |
|---|---|---|---|
| Mouse (desktop) | mouseenter + delay |
mouseleave + delay |
No |
| Keyboard | focusin |
focusout |
No |
| Touch | Long-press (500ms) | Finger release | Yes, after 1500ms |
Keyboard
| Key | Action |
|---|---|
| Escape | Hide tooltip immediately |
Theming
Tooltips use inverted colors — dark background on light mode, light background on dark mode:
| Variable | Usage |
|---|---|
--color-wk-tooltip-bg |
Tooltip background (defaults to text color) |
--color-wk-tooltip-text |
Tooltip text (defaults to background color) |
--size-wk-tooltip-max |
Maximum width (default: 20rem) |
--z-wk-tooltip |
Z-index layer (default: 60) |
Behavior
- Floating UI (bundled ~3.5 KB) positions the tooltip with automatic flip and shift
- Transitions use opacity fade for smooth show/hide
- Livewire SPA navigation closes open tooltips
- Touch devices use long-press (500ms) to trigger, auto-dismiss after 1.5s
Switching a Tooltip Off
A tooltip on a control that has become inert should go quiet. disabled does that:
pointer-events: none on the wrapper is not a way to do this, however much it looks like one. mouseenter is delivered to every ancestor of the element the pointer actually hit, whatever those ancestors' own pointer-events value — so the handler still fires and the panel still appears, over a control that is supposed to be dead.
Following live state
The prop answers for the render that produced it. When the answer changes while the page is open — a sidebar collapses, a row enters a loading state — bind the attribute the component reads instead. No extra prop is involved; it is the same switch, read at the moment the tooltip would open:
{{-- 1. `quiet` is your own Alpine state — anything reactive works. --}}
<div x-data="{ quiet: true }">
{{-- 2. The component reads this attribute when a hover or focus would open
the panel, so it follows the value rather than a snapshot of it. --}}
<x-wirekit::tooltip text="Only while the row is idle"
x-bind:data-wk-tooltip-disabled="quiet ? 'true' : 'false'">
<x-wirekit::button intent="neutral" surface="outline">Retry</x-wirekit::button>
</x-wirekit::tooltip>
{{-- 3. Nothing re-renders and nothing re-initializes when this flips. --}}
<x-wirekit::button x-on:click="quiet = false">Allow it</x-wirekit::button>
</div>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
text |
string|null |
null |
Plain-text tooltip content |
placement |
string |
'top' |
Floating UI placement |
offset |
int |
6 |
Distance in px between trigger and tooltip |
delay-show |
int |
300 |
Delay in ms before showing (desktop hover) |
delay-hide |
int |
100 |
Delay in ms before hiding (desktop mouseleave) |
focusableTrigger |
bool |
true |
Make the trigger keyboard-focusable (WCAG 2.1.1) so the tooltip shows on focus, not just hover. Set false when the slot is already interactive (a button/link) to avoid a double tab-stop. |
disabled |
bool |
false |
Switch the tooltip off without removing it. See below for the live form. |
scope |
string|null |
null |
Scoped personalization key |
Slots
| Slot | Purpose |
|---|---|
| default | The trigger element (hovered/focused to show tooltip) |
content |
Rich HTML tooltip content (alternative to text prop) |
Accessibility
- Trigger:
aria-describedby="{tooltipId}" - Tooltip:
role="tooltip", matchingid - Unique ID generated per tooltip instance
pointer-events: noneon tooltip panel (prevents interaction interference)
Keyboard Interaction
| Key | Action |
|---|---|
Tab (focusing the trigger) |
Show the tooltip |
Tab (away from trigger) |
Hide the tooltip |
Escape |
Hide the tooltip while the trigger keeps focus |
Pitfalls
- Don't put interactive content inside a tooltip. Tooltips are descriptive — buttons, links, and form controls inside them are not reachable by keyboard. Use
<x-wirekit::popover>instead. - Don't use a tooltip as the primary label. Touch users have no hover, and screen readers don't announce tooltip content reliably across browsers. The visible label MUST stand on its own.
Design Tokens
| Token | Used for |
|---|---|
--font-wk-sans |
Tooltip font family |
--text-wk-sm |
Tooltip font size |
--color-wk-tooltip-bg |
Tooltip background |
--color-wk-tooltip-text |
Tooltip text |
--radius-wk-sm |
Border radius |
--shadow-wk-md |
Drop shadow |
--size-wk-tooltip-max |
Maximum width |
--padding-wk-x-sm / --padding-wk-y-xs |
Padding |
--z-wk-tooltip |
Stacking context |
Usage & Conventions
Need a click-triggered hint? A tooltip is hover/focus only by design (the WAI-ARIA tooltip pattern). For a "click the ? icon to reveal a note" affordance — or any content with buttons, links, or form fields — use Popover (click-toggled, full focus management). For rich content that previews on hover, use Hover Card.
Further Reading
- WAI-ARIA Tooltip Pattern — the authoring pattern this component implements
- MDN:
role="tooltip" - Floating UI — positioning engine (bundled, ~3.5 KB)
- Inclusive Components: Tooltips & Toggletips