apx-dsv0.1Local renderer · live
K
Foundations4
  • Getting started
  • Theming
  • Templates
  • Icons
  • Avatar
  • Badge
  • DataGrid
  • Scheduler
  • Stat
  • Table
  • Timeline
  • TreeView
  • Accordion
  • Alert
  • EmptyState
  • Progress
  • Skeleton
  • Spinner
  • SplashScreen
  • Toast
  • ColorPicker
  • FileUpload
  • Form
  • Rating
  • TagsInput
  • Combobox
  • Field
  • Select
  • Toggle
  • Button
  • Calendar
  • Checkbox
  • DatePicker
  • Input
  • NumberInput
  • Radio
  • Slider
  • Switch
  • Textarea
  • AppShell
  • Div
  • Divider
  • Sidebar
  • Stack
  • Typography
  • Image
  • Breadcrumbs
  • Carousel
  • NavigationMenu
  • Pagination
  • Stepper
  • Tabs
  • Toolbar
  • CommandPalette
  • Confirm
  • Drawer
  • HoverCard
  • Menu
  • Modal
  • Popover
  • Tooltip
  • Icon
  • Card
  • PricingCard
60 componentsapx-ds/renderer
Tooltip
Variant↳ other

Overlays

Tooltip

Hover/focus hint primitive. First overlay consumer of the positioning engine — anchored placement with auto-flip, optional arrow, hover/focus delay state, and ARIA-correct describedby pairing with the trigger.

Overview

<Tooltip /> is the canonical hover/focus hint primitive. Wrap any single trigger element to attach a small floating message that opens on hover and on keyboard focus.

Overview — tooltips at top, right, bottom, and left

Loading preview…
Overview.tsx

Tooltip is intentionally read-only — its surface has pointer-events: none and never receives focus. For interactive overlays (rich content, links, buttons-inside-the-floater), reach for <Popover /> instead.

When to use

  • Quick clarification for an icon-only button: <Tooltip content="Save changes"><Button leftIcon={…} aria-label="Save" /></Tooltip>.
  • Disambiguating a truncated label or a status indicator.
  • Surfacing a keyboard shortcut: <Tooltip content={<>Save · <Kbd>⌘S</Kbd></>}>…</Tooltip>.
  • Showing extra metadata (timestamps, IDs) without crowding the visible UI.

When NOT to use

  • The content is interactive — use <Popover />.
  • The information is critical — Tooltips are skipped on touch devices and read by screen readers via aria-describedby (associative, not announced as a live region). Critical info belongs in the visible UI.
  • The trigger is wrapped twice. Tooltip clones a single child; multi-element triggers must wrap in a <span> first.

Anatomy

text
[ trigger ] ──hover/focus──▶ ┌──────────────────┐
                             │ content + arrow  │
                             └──────────────────┘
[ trigger ] ──hover/focus──▶ ┌──────────────────┐
                             │ content + arrow  │
                             └──────────────────┘
  • trigger — your single React element. Tooltip clones it to attach ref, aria-describedby, and pointer / focus handlers.
  • content — the floating surface. Carries role="tooltip" and a generated id that the trigger references via aria-describedby while open.
  • arrow — optional SVG arrow that points back at the trigger after Floating UI's flip() resolves. Toggle with showArrow={false}.

Variants

Pick by how the tooltip should integrate with the surface beneath it:

  • solid — opaque fill + contrast text. Default. The conventional tooltip look.
  • outline — paper background, 1px colored border + colored text. Brand-aligned hints (link previews, primary actions).
  • soft — subtle tinted background + colored text + low-opacity colored border. Editorial / settings-pane tooltips; calmer than solid.
  • inverted — platform-default light-on-dark / dark-on-light. Ignores color — the inverted variant has a fixed dark/light contrast palette so it works on every brand.

The 4 variants × 7 colors compound matrix mirrors Badge's shape exactly.

Sizes

SizePaddingFontMax-widthArrow size
smpx-2 py-1text-xsmax-w-xs12×6
mdpx-2.5 py-1.5text-smmax-w-sm16×8
lgpx-3 py-2text-basemax-w-md20×10

Placement

12 placements — top / right / bottom / left × start / center / end. Floating UI's flip middleware automatically swaps to the opposite side at viewport edges, and the start / end alignment uses logical properties so RTL falls out automatically: top-start is top-left in LTR and top-right in RTL.

The post-flip placement is reflected on the floating element via data-placement so consumers who care about animation direction or arrow rotation can branch on it.

Delay state

Two timers control hover behaviour:

  • openDelay (default 400ms) — filters out accidental sweeps across the UI. Matches MUI / Radix UX research findings on attention thresholds.
  • closeDelay (default 150ms) — gives users time to move the cursor onto the floating surface. Hovering the surface itself cancels the close timer, so users can move from trigger → tooltip without it disappearing.

Set both to 0 for instant tooltips; set high values (~1000ms+) for "patient" tooltips that only appear on deliberate hovers.

Accessibility

  • Floating surface carries role="tooltip" and a generated id. The trigger gets aria-describedby="<id>" while open — exactly the ARIA Tooltip pattern.
  • Existing aria-describedby values on the trigger are preserved (the new id is appended).
  • Tooltip opens on pointerenter (mouse, pen, touch on platforms that emit it) and focus (keyboard). It closes on pointerleave, blur, and Escape.
  • The escape stack ensures only the topmost tooltip closes on Escape, not all open overlays.
  • Tooltip never receives focus itself (pointer-events-none + no tabIndex) — content is not interactive. For interactive overlays use <Popover />.
  • The arrow carries aria-hidden="true".
  • disabled={true} skips all opening logic; the trigger renders normally.
  • axe-core: zero violations across every variant × color cell.

Examples

Basic

Loading preview…
Basic.tsx

Variants

Loading preview…
Variants.tsx

Sizes

Loading preview…
Sizes.tsx

Colors

Loading preview…
Colors.tsx

Placements

Loading preview…
Placements.tsx

Delay

Loading preview…
Delay.tsx

WithoutArrow

Loading preview…
WithoutArrow.tsx

LongContent

Loading preview…
LongContent.tsx

Disabled

Loading preview…
Disabled.tsx

Controlled

Loading preview…
Controlled.tsx

PortalContainer

Loading preview…
PortalContainer.tsx

Theming

Theme-level overrides flow through useThemedClasses exactly like every other DS component:

tsx
defineTheme({
  components: {
    Tooltip: {
      defaultProps: { variant: 'inverted', size: 'sm', openDelay: 200 },
      styleOverrides: {
        content: 'shadow-lg',
        arrow: '',
      },
    },
  },
});
defineTheme({
  components: {
    Tooltip: {
      defaultProps: { variant: 'inverted', size: 'sm', openDelay: 200 },
      styleOverrides: {
        content: 'shadow-lg',
        arrow: '',
      },
    },
  },
});

Per-instance overrides via className / sx / style are merged on top of the theme overrides, which are merged on top of the recipe — same precedence as everywhere else in the DS.

Props

PropTypeDefaultDescription
children*ReactElement<unknown, string | JSXElementConstructor<any>>—The trigger. Must be a single React element — Tooltip clones it to attach the position ref, pointer / focus handlers, and `aria-describedby` while open. Wrap multi-element triggers in a `<span>` first.
content*ReactNode—The hint text or rich content rendered inside the floating surface.
closeDelaynumber—Hover-out delay in ms. The close timer is cancelled when the cursor enters the tooltip surface itself, letting users move from trigger to tooltip without it vanishing. Default: `150`.
colorResponsiveValue<TooltipColor>—Palette role. Ignored when `variant === 'inverted'` (the inverted variant has a fixed dark/light contrast palette). Default: `'neutral'`.
defaultOpenboolean—Initial `open` for the uncontrolled case. Default: `false`.
disabledboolean—When `true`, the tooltip never opens. The trigger renders normally (no ref forwarding, no pointer / focus handlers) so consumers can re-use the same prop to "disable hint" without re-mounting the trigger element.
offsetnumber—Px gap between the trigger edge and the tooltip surface. Default: `6`.
onOpenChange(open: boolean) => void—Notified whenever the `open` value changes (controlled or uncontrolled).
openboolean—Controlled `open`. When omitted, the tooltip manages its own state via `defaultOpen`.
openDelaynumber—Hover-in delay in ms. Filters out accidental sweeps across the UI; matches MUI / Radix UX research findings on attention thresholds. Default: `400`.
placementResponsiveValue<TooltipPlacement>—Preferred placement; Floating UI's `flip` middleware may swap to the opposite side.
portalContainerHTMLElement | null—Override the portal target. `null` and `undefined` both fall back to `document.body`. Pass a ref'd modal body when nesting tooltips inside an overlay so they don't appear above it.
showArrowboolean—Render an arrow that points back at the trigger. Default: `true`.
sizeResponsiveValue<TooltipSize>—Size scale. Default: `'md'`.
styleCSSProperties—Inline style on the floating surface. Merged after recipe + sx + Floating UI's positioning styles.
sxSx—Theme-aware inline style object. Merged after the recipe's `style`.
variantResponsiveValue<TooltipVariant>—Visual chrome. Default: `'solid'`.