Skip to main content

Tooltip

MD3 tooltip: a short label (plain) or a richer card with a subhead and actions (rich), attached to a single trigger element. The popup renders in the top layer and flips / clamps to stay inside the viewport.

Plain​

Hover the trigger, focus it with the keyboard, or long-press it on touch. Plain tooltips briefly describe icon buttons and other compact controls.

<Tooltip text="More information">
<IconButton icon={<Info />} aria-label="Info" variant="standard" />
</Tooltip>

Rich​

A rich tooltip adds a subhead and up to two text-button actions, laid out side by side.

<Tooltip
variant="rich"
subhead="Rich tooltip"
text="Rich tooltips support a subhead, longer body text, and an action."
action={<Button variant="text" size="xs">Learn more</Button>}
>
<Button variant="outlined">Hover or focus me</Button>
</Tooltip>

Persistent​

persistent rich tooltips open and close on click / tap of the trigger (hover, focus and long-press don't open them) and stay open until the user presses elsewhere, presses Escape, or moves focus away. Recommended when the tooltip has an action; avoid it on icon buttons.

<Tooltip
variant="rich"
persistent
subhead="New: shared albums"
text="Invite people to add their photos to an album you share with them."
action={<Button variant="text" size="xs">Learn more</Button>}
>
<Button variant="filled">Share album</Button>
</Tooltip>

Placement​

placement is the preferred side — 'top' by default for plain tooltips, 'bottom' for rich ones. The tooltip flips to the other side when there is no room and is always kept inside the viewport. Inside a top app bar, use 'bottom'.

<Tooltip text="Shown below" placement="bottom">
<Button variant="tonal">Bottom</Button>
</Tooltip>

Controlled​

Visibility is uncontrolled by default (defaultOpen); pass open together with onOpenChange to control it.

const [open, setOpen] = useState(false)

<Tooltip text="Copy link" open={open} onOpenChange={setOpen}>
<Button>Share</Button>
</Tooltip>

Accessibility​

  • Opens on hover, keyboard focus, or touch long-press, and stays open while the pointer or focus is on the trigger or on the tooltip itself. It closes 1.5 s after they leave, on Escape (wherever focus is), or on a press elsewhere — hoverable, dismissible and persistent per WCAG 1.4.13. Only one tooltip is open at a time.
  • While open, the trigger gets aria-describedby pointing at the popup, which has role="tooltip".
  • A rich tooltip with an action becomes a non-modal role="dialog" labelled by its subhead, and its actions are reachable with Tab from the trigger.
  • The tooltip describes its trigger; it does not name it. Icon-only triggers still need their own aria-label.

Props​

PropTypeDefaultDescription
actionReactNode—Rich tooltip action(s) — up to two text buttons, laid out side by side. A rich tooltip with an action becomes a non-modal `role="dialog"` whose actions are reachable with Tab from the trigger; consider `persistent`.
children *ReactElement<unknown, string | JSXElementConstructor<any>>—The trigger element (a single focusable/hoverable element).
defaultOpenbooleanfalseUncontrolled initial visibility.
onOpenChange((open: boolean) => void)—Notified when visibility should change.
openboolean—Controlled visibility.
persistentbooleanfalsePersistent rich tooltip: opens and closes on click / tap of the trigger (hover, focus and long-press don't open it) and stays open until the user interacts elsewhere (outside press, Escape, or focus leaving the trigger and tooltip). Recommended when the tooltip has an `action`; avoid it on icon buttons.
placementenum'top' for plain, 'bottom' for richPreferred placement relative to the trigger. The tooltip flips to the other side when there is no room and is kept inside the viewport. Inside a top app bar, use `'bottom'`.
subheadReactNode—Rich tooltip subhead (title).
textReactNode—Body / supporting text.
variantenumplainPlain style or rich (with subhead + action).