Tooltip
A few words about the thing under the pointer or the focus. It says, and it never asks: nothing inside a tooltip can be clicked.
Try it
Rest the pointer on a button, or Tab to it. Move onto the tooltip and it stays; press Esc and it goes, with the focus left where it was.
Choosing a tooltip
A tooltip is for what helps and can be done without: the name of an icon, a shortcut, the reason behind a badge. It cannot be reached by touch, so whatever a reader needs in order to go on belongs on the page, as the Field’s description or an inline message. It opens on hover and on focus, so its trigger has to be something the keyboard can reach.
That rules out a disabled button. The pointer would still find the tooltip, and the keyboard never could: a disabled control takes no focus. The reason something cannot be done yet belongs beside it, in words everyone gets.
If anything inside has to be pressed — a link, a button, a field — it is not a tooltip. That is a popover, opened by a click, and it is the next thing to be built on this same surface. And a tooltip is never the place for an error: errors stay where the reader is looking.
Two sizes, one surface
| Part | md — drawn | sm |
|---|---|---|
| Padding | 20 | 6 block, 12 inline |
| Radius | 12 | 8 |
| Text, Medium | 14 / 22 | 12 / 16 |
| Description | 12 / 16, 16 above | — |
| Widest | 266 | 240 |
| From the trigger | 8 | 8 |
md is the card as drawn, for an explanation: lines with an icon, and a quieter paragraph beneath. sm was added for the word or two on an icon button, where 20 of padding is too much. Both are the overlay surface with the same edge and the same shadow. Left to itself, a string is sm and anything richer is md.
Where it leaves the drawing
Most systems draw the tooltip on an inverse surface, dark on a light page. This one is drawn on the overlay surface, the menu’s, and stays there: what tells a tooltip from a menu is that it holds nothing to press, not its colour.
The drawn edge is a grey between two of the theme’s border tokens. The stronger of the two was tried and is too strong for a panel that already has a shadow, so the tooltip takes the subtle one until the border tokens between them exist. Dark was not drawn: it is the overlay surface, a step above a card, with the same edge rather than the stronger one the menu takes.
There is no arrow. The panel flips to the other side when it does not fit, and the stylesheet cannot yet know which way it went, so an arrow would point the wrong way exactly when it mattered.
Accessibility
The tooltip describes its trigger through aria-describedby, added to whatever description the trigger already has. For a button that shows only an icon, purpose="label" makes the tooltip the button’s name instead. It opens at once on keyboard focus and after 400ms under the pointer, so a pointer crossing the page leaves no trail. A focus that came from a click does not open it.
| It must be | So |
|---|---|
| Hoverable | The pointer can move from the trigger onto the tooltip. It has 100ms to cross the 8px between them. |
| Dismissible | Esc closes it, and neither the pointer nor the focus has to move. |
| Persistent | It stays until the pointer or the focus leaves, Esc, or a press of the trigger. It never times out. |
It is a manual popover in the top layer, placed by CSS anchor positioning: no z-index, no portal, and an open menu or date picker stays open beneath it. In a browser without anchor positioning it is not shown at all, rather than shown in the middle of the screen; its words still reach a screen reader. The trigger is wrapped in an inline box that does not stretch, so a full-width trigger needs className on the Tooltip to fill its row.
Props
| Prop | Type | Default |
|---|---|---|
content | React | required |
children | React | required |
description | string | — |
shortcut | string | — |
size | 'sm' | 'md' | 'sm' for a string, else 'md' |
placement | 'top' | 'bottom' | 'start' | 'end' | 'top' |
purpose | 'describe' | 'label' | 'describe' |
className | string | — |