Tooltip
Tooltip
Shows on hover or keyboard focus of its anchor and hides on leave or blur, with no wiring beyond an `anchorRef`.
import { useRef } from 'react'
import { Icon, IconButton, Surface, Text, Tooltip } from '@language-lit/material3-expressive'
export function TooltipExample() {
const plainAnchorRef = useRef<HTMLButtonElement>(null)
const richAnchorRef = useRef<HTMLButtonElement>(null)
const startAnchorRef = useRef<HTMLButtonElement>(null)
const endAnchorRef = useRef<HTMLButtonElement>(null)
const richNoSubheadAnchorRef = useRef<HTMLButtonElement>(null)
return (
<Surface
as="section"
aria-labelledby="tooltip-example-title"
color="surface-container-low"
shape="extra-large"
className="tooltip-example"
>
<Text as="h2" id="tooltip-example-title" variant="titleLarge" emphasis="emphasized">
Tooltip
</Text>
<Text as="p" variant="bodyMedium">
Shows on hover or keyboard focus of its anchor and hides on leave or
blur, with no wiring beyond an `anchorRef`.
</Text>
<div className="tooltip-example__row">
<IconButton ref={plainAnchorRef} aria-label="Favorite" variant="standard">
<Icon source="star" />
</IconButton>
<Tooltip anchorRef={plainAnchorRef} content="Add to favorites" />
<IconButton ref={richAnchorRef} aria-label="Storage info" variant="standard">
<Icon source="info" />
</IconButton>
<Tooltip
anchorRef={richAnchorRef}
variant="rich"
subhead="Storage"
content="12 of 15 GB used. Free up space by removing unused files."
placement="bottom"
/>
<IconButton ref={startAnchorRef} aria-label="Undo" variant="standard">
<Icon source="undo" />
</IconButton>
<Tooltip anchorRef={startAnchorRef} content="Undo" placement="start" />
<IconButton ref={endAnchorRef} aria-label="Redo" variant="standard">
<Icon source="redo" />
</IconButton>
<Tooltip anchorRef={endAnchorRef} content="Redo" placement="end" />
<IconButton ref={richNoSubheadAnchorRef} aria-label="Sync status" variant="standard">
<Icon source="cloud_done" />
</IconButton>
<Tooltip
anchorRef={richNoSubheadAnchorRef}
variant="rich"
content="All changes are synced to the cloud."
/>
</div>
</Surface>
)
}Tooltip renders a portaled, non-interactive description anchored to a
trigger you already render. Unlike Menu, it wires its own show/hide
interaction — hover, focus, and Escape — directly on your anchor, so there
is nothing else to wire up.
import { useRef } from 'react'
import { Icon, IconButton, Tooltip } from '@language-lit/material3-expressive'
import '@language-lit/material3-expressive/styles.css'
const anchorRef = useRef<HTMLButtonElement>(null)
<IconButton ref={anchorRef} aria-label="Favorite">
<Icon source="star" />
</IconButton>
<Tooltip anchorRef={anchorRef} content="Add to favorites" />Contract
anchorRefpoints at a trigger you render and own completely, the same trigger-agnostic contractMenu/Dialogalready use. UnlikeMenu, your trigger needs no click/aria-expandedwiring of its own —Tooltipattaches hover/focus listeners to the anchor directly and managesaria-describedbyon it imperatively while shown.contentis the required body.variant(default'plain') or'rich'adds an optionalsubheadabovecontentand uses a larger container. Both variants stay non-interactive:role="tooltip"disallows focusable content, so there is no action-button variant.placement(default'top') accepts'top','bottom','start', or'end'; it flips to the opposite side when the preferred one would collide with the viewport edge.open/defaultOpen/onOpenChangeexist as a controlled escape hatch for advanced cases, following the same shape as every other stateful component.
Behavior
Shown immediately on hover or keyboard focus of the anchor; hidden
immediately on hover-out or blur, unless the pointer has moved onto the
tooltip's own popover, which keeps it open. Escape always dismisses it.
Positioning centers on the cross axis, flips to the opposite side on
collision, and clamps flush to the viewport edge — it repositions on scroll
and window resize while open.
Tokens and boundaries
All color, geometry, and motion values live in one --m3e-comp-tooltip-*
registration, split into plain-* and rich-* groups for the two
variants. Theme overrides remain scoped to Material3Provider; Tooltip
injects no runtime styles. It imports no Next.js, Vite,
router, animation library, or private application code.