Skip to main content
BM

Tooltip

A short hint for one control, on hover and keyboard focus: what it does, or the name of an icon-only control.

View source on GitHub

Copies a link to this page
TooltipExample.tsx
import { Button } from "@/components/Button";
import { Tooltip } from "@/components/Tooltip";

export function TooltipExample() {
  return (
    <Tooltip content="Copies a link to this page">
      <Button iconStart="copy">Share</Button>
    </Tooltip>
  );
}

Examples

Description

Saves without publishing

Announced as: “Save draft, button, Saves without publishing”

Icon-only names

No tooltip on the last: nameTooltip={false}.

Sides

Shown on the top sideShown on the bottom sideShown on the start sideShown on the end side

Disabled reason

Add a title first

Press or tap it to see why it's disabled.

In running text

Browse the token galleryEvery color, type and space token for every value the components use.

Controlled

Pinned open from outside

The tooltip is hidden.

Customized with component tokens

Violet, from the accent-2 fill
CSS
.customTooltip {
  --component-tooltip-background: var(--color-accent-2-fill);
  --component-tooltip-text: var(--color-accent-2-fill-text);
}

Props

Any native prop not listed here goes to the root element unchanged.

Its one child is the trigger: a focusable element that takes a ref and DOM props, as every library control does. content holds no links, buttons or other interactive content. Use kind="name" only when content repeats the trigger's accessible name. className and other native props go to the tooltip popup.

Tooltip props
PropTypeDefaultDescription
contentReactNode—Required. The tooltip's text. No links, buttons or other interactive content.
kind"description" | "name""description""description" becomes the trigger's accessible description. "name" only shows the trigger's name and isn't announced: use it only when content matches that name.
side"top" | "bottom" | "start" | "end""top"The side of the trigger it shows on, centered. It flips when it doesn't fit, and shifts to stay in the viewport.
openboolean—Controlled open state; pair with onOpenChange.
defaultOpenbooleanfalseUncontrolled initial state.
onOpenChange(open: boolean) => void—Called on every requested show or hide, controlled or not: hover, focus, Escape, a press, and another tooltip showing.

Component tokens

Tooltip component tokens
TokenCopyDescriptionAliasesLightDarkPreview
--component-tooltip-backgroundBubble and arrow fill.color.surface.inverse#17202bfrom color.gray.900#e6effffrom color.slate.50
--component-tooltip-textTooltip text.color.text.inverse#fbf8f2from color.sand.50#0b1220from color.slate.950
--component-tooltip-border-widthBubble and arrow outline: transparent, drawn only in forced colors.effect.border.width2pxfrom effect.line.22pxfrom effect.line.2
--component-tooltip-radiusBubble corner radius.radius.control4pxfrom radius.44pxfrom radius.4
--component-tooltip-padding-blockBlock padding of the bubble.space.stack.xs0.25remfrom space.10.25remfrom space.1
--component-tooltip-padding-inlineInline padding of the bubble.space.inset.sm0.5remfrom space.20.5remfrom space.2
--component-tooltip-max-widthWidest bubble; the text wraps beyond it (and it's never wider than the viewport less twice the offset).size.column.md16remfrom size.6416remfrom size.64
--component-tooltip-font-familyTooltip text font.type.family.body'Inter Variable', 'Inter Fallback', system-ui, -apple-system, 'Segoe UI', Roboto, sans-seriffrom type.font-stack.sans'Inter Variable', 'Inter Fallback', system-ui, -apple-system, 'Segoe UI', Roboto, sans-seriffrom type.font-stack.sans
--component-tooltip-font-sizeTooltip text size.type.size.small0.875remfrom type.font-size.sm0.875remfrom type.font-size.sm
--component-tooltip-font-weightTooltip text weight.type.weight.body400from type.font-weight.400400from type.font-weight.400
--component-tooltip-name-font-weightWeight of the name line above a disabled button's reason.type.weight.strong600from type.font-weight.600600from type.font-weight.600
--component-tooltip-line-heightTooltip line height.type.leading.body1.6from type.line-height.normal1.6from type.line-height.normal
--component-tooltip-offsetGap to the trigger, and from the viewport edge when shifted.space.stack.sm0.5remfrom space.20.5remfrom space.2
--component-tooltip-arrow-sizeSide of the arrow's rotated square.space.stack.sm0.5remfrom space.20.5remfrom space.2
--component-tooltip-transition-durationDuration of the fade (0ms under reduced motion).motion.duration.fast150msfrom motion.time.150Reduced motion: 0ms150msfrom motion.time.150No preview
--component-tooltip-transition-easingEasing of the fade.motion.easing.entercubic-bezier(0, 0, 0.2, 1)from motion.curve.outcubic-bezier(0, 0, 0.2, 1)from motion.curve.outNo preview

Accessibility

  • A "description" tooltip has role="tooltip" and becomes the trigger's accessible description. A "name" tooltip repeats the trigger's name for sighted users, hidden from assistive technology so the name isn't announced twice.
  • Its text is in the page from the start, so the description is there before JavaScript loads and without hovering.
  • It shows after a 300ms hover, and at once while moving along a row of controls. Keyboard focus shows it at once, since a keyboard user has nothing else to wait for; focus from a mouse press doesn't, and neither does focus coming back from the trigger's own menu.
  • It stays until dismissed: Escape, moving the pointer off both the trigger and the tooltip, moving focus away, or pressing the trigger. The pointer can move onto it, and it never hides on a timer (WCAG 1.4.13).
  • Around a library control, one bubble shows: the control's disabledReason while it's disabled, and this content otherwise. An icon-only control's name tooltip steps aside; its name is still its accessible name, and both descriptions are announced.
  • Touch shows no tooltips, except a disabled Button's reason, which a tap shows and a tap elsewhere hides.
  • Never put essential information only in a tooltip: many visitors never see it.
  • It fades over component.tooltip.transition-duration, 0ms under reduced motion.
  • In forced colors, the bubble and its arrow are outlined in a system color.
Tooltip keyboard
KeyAction
TabMoves focus to the trigger, which shows its tooltip.
EscapeHides the tooltip; focus stays on the trigger.