Tooltip
Use tooltip with the current published Askr packages.
@askrjs/ui/tooltip0.0.13@askrjs/themes/tooltip0.0.13
How to use tooltip
Tooltip should use the standard themed surface unless the application is deliberately implementing its own design system on top of @askrjs/ui.
- Import the themed component from @askrjs/themes/components; use @askrjs/ui directly only when building a custom visual system.
- Keep tooltip labels, state, and application actions visible at the call site instead of styling internal DOM nodes.
- Verify keyboard behavior, focus movement or return, disabled state, and both standard themes.
import { Button, Tooltip, TooltipContent, TooltipTrigger } from '@askrjs/themes/components';
<Tooltip>
<TooltipTrigger asChild><Button aria-label="Archive project">Archive</Button></TooltipTrigger>
<TooltipContent>Move this project to the archive</TooltipContent>
</Tooltip>Purpose
Tooltip shows a short hint tied to an element, opened by hover or keyboard focus rather than a click. It's the right choice for a one-line label or clarification an icon button needs; once the content grows into something a user has to read or interact with, reach for Popover or Hover Card instead. Because it opens on focus, it also doubles as an accessible-name fallback for icon-only triggers.
Install and import
The headless behavior lives at `@askrjs/ui/tooltip`, exporting `Tooltip`, `TooltipTrigger`, `TooltipPortal`, and `TooltipContent`. Most apps won't import from there directly — pull the styled version from `@askrjs/themes/tooltip`, which wraps the same primitives with the default theme's positioning and animation CSS already applied.
Live examples
A minimal tooltip is a `Tooltip` wrapping a `TooltipTrigger` and a `TooltipContent` inside `TooltipPortal`, with the trigger set to whatever element the hint describes — commonly an icon `Button`. Toggling `side` and `align` on `TooltipContent` is the fastest way to see how the positioning engine reacts to different anchor placements before wiring up real content.
Anatomy
`Tooltip` is the state root; `TooltipTrigger` is the hover/focus target and takes the same props as a button-like element. `TooltipPortal` renders `TooltipContent` outside the normal DOM flow so it isn't clipped by an ancestor's `overflow: hidden`, and `TooltipContent` is the actual bubble, positioned relative to the trigger.
State model
Openness is a plain boolean on the root: pass `open` and `onOpenChange` to drive it from outside, or let `defaultOpen` seed uncontrolled behavior and manage it internally. There's no separate state for hover versus focus — both funnel into the same `open` value, so you don't need to reconcile two code paths for pointer and keyboard users.
Keyboard and accessibility
The content renders with `role="tooltip"` and the trigger gets `aria-describedby` pointing at it, per `TOOLTIP_A11Y_CONTRACT` — so screen readers announce the hint as a description of the trigger, not as a separate focusable region. Focusing the trigger with the keyboard opens it the same as hovering does, and moving focus away closes it; there's no dedicated close button or additional tab stop to manage.
Styling and tokens
`TooltipContent` picks up `data-state`, `data-side`, `data-align`, and `data-disabled` attributes, which is what the default theme's CSS hooks into for entrance/exit transitions and directional arrow placement. Stacking is controlled by the shared overlay z-index scale, where tooltips sit above toasts at `var(--ak-z-tooltip, 1600)` so they're never hidden behind other overlay layers.
API
`TooltipContent` accepts `forceMount`, `side`, `align`, and `sideOffset` on top of standard div props — `forceMount` keeps it in the DOM even when closed, which matters if you're animating exit with CSS rather than unmounting. `TooltipTrigger` takes the same prop surface as any button-like Askr primitive, including an `asChild`-style variant for rendering a custom trigger element.
Edge cases
Tooltips don't fire from a touch tap the way hover-based UI generally doesn't on touch devices, so don't rely on tooltip content to convey anything essential — treat it as supplementary. If the trigger is disabled, `data-disabled` is still set for styling, but you're responsible for deciding whether a disabled control should still explain itself via tooltip. Rapid focus changes between adjacent triggers can also cause overlapping open/close transitions if your CSS doesn't account for the interrupted `data-state`.
Related pages
See Popover for click-triggered, persistently-open content, and Hover Card for richer hover-triggered previews that can contain interactive elements. Dropdown and Menu cover the click-to-open, keyboard-navigable list pattern that Tooltip intentionally doesn't attempt.