# Tooltip

A few words on a small label plate, the kind riveted beside a control on a rack: printed in the contrast colours with a rule just inside its edge and a short tab aimed at its key. It comes up when a pointer rests on the key or the keyboard reaches it, is read by a screen reader, and goes on Escape.

Kit part · Free · https://tactileui.dev/parts/tooltip

- Element: `data-tip`
- Needs: `kit.css` and `kit.mjs` ([how to install the kit](https://tactileui.dev/docs/installation#the-kit))
- Categories: Tooltips
- Finishes: Aluminium, Graphite, Oak, Walnut, Porcelain, Black, Daylight, Night, Paper, Phosphor, E-paper, AMOLED
- Volumes: Tactile, Quiet

## Variants

### Above · the default

```html
<span style="display:inline-flex;flex-direction:column;align-items:center;gap:8px;white-space:nowrap"><span class="tui-tooltip" data-static="top" aria-hidden="true"><span class="tui-tooltip__text">Play</span></span><button type="button" class="tui-key tui-key--icon" aria-label="Play" tabindex="-1"><svg class="tui-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 3.5v9l7-4.5z"/></svg></button></span>
```

### With a shortcut

```html
<span style="display:inline-flex;flex-direction:column;align-items:center;gap:8px;white-space:nowrap"><span class="tui-tooltip" data-static="top" aria-hidden="true"><span class="tui-tooltip__text">Search the reel</span><span class="tui-tooltip__kbd" aria-hidden="true"><span>Ctrl</span><span>K</span></span><span class="tui-tooltip__sr">, Control K</span></span><button type="button" class="tui-key tui-key--icon" aria-label="Search the reel" tabindex="-1"><svg class="tui-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="7" cy="7" r="4.2"/><path d="m10.2 10.2 3.3 3.3"/></svg></button></span>
```

### Below · flipped at the top edge

```html
<span style="display:inline-flex;flex-direction:column;align-items:center;gap:8px;white-space:nowrap"><button type="button" class="tui-key tui-key--icon" aria-label="Sound" tabindex="-1"><svg class="tui-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 11.2V7.3a4 4 0 0 1 8 0v3.9l1.3 1.3H2.7z"/><path d="M6.7 14.3h2.6"/></svg></button><span class="tui-tooltip" data-static="top" aria-hidden="true"><span class="tui-tooltip__text">Turn sound on</span></span></span>
```

### Beside · data-tip-side

```html
<span style="display:inline-flex;flex-direction:row;align-items:center;gap:8px;white-space:nowrap"><button type="button" class="tui-key tui-key--icon tui-key--round" aria-label="Power" tabindex="-1"><svg class="tui-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 2.5v5"/><path d="M4.6 4.6a5 5 0 1 0 6.8 0"/></svg></button><span class="tui-tooltip" data-static="right" aria-hidden="true"><span class="tui-tooltip__text">Power</span></span></span>
```

### Describing a key with words

```html
<span style="display:inline-flex;flex-direction:column;align-items:center;gap:8px;white-space:nowrap"><span class="tui-tooltip" data-static="top" aria-hidden="true"><span class="tui-tooltip__text">Moves it out of the inbox</span></span><button type="button" class="tui-key" tabindex="-1">Archive</button></span>
```

### Without the script · the same plate

```html
<span style="display:inline-block;padding-top:34px"><button type="button" class="tui-key tui-key--icon is-tip" data-tip="Record" aria-label="Record" tabindex="-1"><svg class="tui-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><g fill="currentColor" stroke="none"><circle cx="8" cy="8" r="4"/></g></svg></button></span>
```

## Every state

- Rest
- Pointer resting
- Keyboard focus
- After Escape
- At the top edge

Hover, pressed and focus are forced with `.is-hover`, `.is-down` and `.is-focus`; checked and disabled are real.

## API

| Name | Kind | Values | What it does |
| - | - | - | - |
| data-tip | attribute | text | The words. Upgraded to a plate with role="tooltip" when the script loads; drawn from CSS until then. |
| data-tip-side | attribute | top · bottom · left · right | Where it prefers to hang (top). It flips to the other side, or slides along, to stay on screen. |
| data-tip-kbd | attribute | Mod+K | A shortcut printed after the words, ⌘ on a Mac and Ctrl elsewhere, and set as aria-keyshortcuts on the key. |
| data-tooltip | attribute | id | Use a .tui-tooltip written in the page instead of the words of data-tip. |
| aria-describedby · aria-labelledby | set by the script | the plate’s id | Described by the plate; a trigger with no name of its own is named by it instead. Ids already there are kept. |
| .tui-tooltip | class | role="tooltip" | The plate. data-placed says the side it took; data-static draws one in the page. |
| Escape | key | while one is out | Puts it away and does nothing else, so a dialog behind it stays open. It stays away until the key is left. |
| TIP_HOVER_MS · TIP_FOCUS_MS | constant | 400 · 120 | The rest before it shows for a pointer, and for focus. Once one has been out, the next shows at once. |
| tooltipPlacement · tooltipHTML · keyShortcuts | function | kit.mjs | The placement arithmetic, the plate’s inside as markup, and the aria-keyshortcuts value. Pure. |

## Markup

```html
<button class="tui-key tui-key--icon" aria-label="Play" data-tip="Play">
  <svg …></svg>
</button>

<!-- A shortcut, printed after the words and set as aria-keyshortcuts -->
<button class="tui-key tui-key--icon" aria-label="Search the reel"
        data-tip="Search the reel" data-tip-kbd="Mod+K">…</button>

<!-- Another side: top (default), bottom, left, right -->
<button class="tui-key tui-key--icon" aria-label="Power" data-tip="Power" data-tip-side="right">…</button>

<!-- Your own plate, written in the page -->
<button class="tui-key" data-tooltip="tip-archive">Archive</button>
<div class="tui-tooltip" id="tip-archive">Moves it out of the inbox</div>
```

```js
import '/kit/kit.mjs';   // or just '/kit/parts/tooltip.mjs'

// Every [data-tip] is upgraded on import, and any added later. Change the words
// at any time; the plate and what a screen reader hears follow.
key.dataset.tip = playing ? 'Pause' : 'Play';
```

The demo on the page:

```html
<div style="display:grid;gap:22px;justify-items:center;padding:34px 0 8px">
  <div class="tui-tray" role="toolbar" aria-label="Reel">
    <button type="button" class="tui-key tui-key--icon" aria-label="Rewind" data-tip="Rewind"><svg class="tui-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13 8H3"/><path d="M7.4 4.6 4 8l3.4 3.4"/></svg></button>
    <button type="button" class="tui-key tui-key--icon" aria-label="Play" data-tip="Play"><svg class="tui-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 3.5v9l7-4.5z"/></svg></button>
    <button type="button" class="tui-key tui-key--icon" aria-label="Record" data-tip="Record"><svg class="tui-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><g fill="currentColor" stroke="none"><circle cx="8" cy="8" r="4"/></g></svg></button>
    <button type="button" class="tui-key tui-key--icon" aria-label="Search the reel" data-tip="Search the reel" data-tip-kbd="Mod+K"><svg class="tui-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="7" cy="7" r="4.2"/><path d="m10.2 10.2 3.3 3.3"/></svg></button>
  </div>
  <div style="display:flex;gap:10px;flex-wrap:wrap;justify-content:center">
    <button type="button" class="tui-key" data-tip="Moves it out of the inbox; nothing is deleted">Archive</button>
    <button type="button" class="tui-key tui-key--icon tui-key--round" aria-label="Power" data-tip="Power" data-tip-side="right"><svg class="tui-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 2.5v5"/><path d="M4.6 4.6a5 5 0 1 0 6.8 0"/></svg></button>
  </div>
</div>
```

## Usage notes

Rest the pointer on a key, or Tab to one: the plate comes up after a beat, and the next one at once. Escape puts it away. The power key hangs its plate to the right; scroll it to the top of the window and the plates below the bar flip.

## Accessibility

- The plate is a real element with `role="tooltip"`, and the key points at it with `aria-describedby`, so a screen reader reads the words after the key’s name. A key with no name at all is named by the plate.
- It comes up on keyboard focus as well as on a resting pointer, and Escape puts it away without moving focus or closing anything behind it (WCAG 1.4.13).
- The pointer can move onto the plate without it going, so a magnifier user can read it. It holds nothing to press.
- It never sits over its key: it flips to the other side, or slides along the edge, to stay on screen at any width.
- Touch never opens it, so an icon key must be named by its `aria-label`. The shortcut’s symbols are named for a screen reader: “Control K”.
- With reduced motion it appears without fading.

## How it’s built

The script makes one small plate per key at the end of the page, a manual popover, so it is drawn in the top layer above any card or scrolling box and never clipped. It is placed by the popover part’s arithmetic with a 6px corner and an 8px gap, then its tab is aimed at the key’s centre. The plate is the contrast cap’s colours with an outline set 3px inside its edge, printed, not raised; in Quiet its shadow is the volume’s hairline, on paper it is flat and in the mono face. Without the script the same plate is drawn from `data-tip` with `::after`, and stands down once the script has the key.

## Rules

Name an icon key in a word or two, for the eye and the ear alike, and get out of the way the moment it is not wanted.

The full rules are in `tooltip.rules.md` in the brain, which ships with the Kit.

## Related parts

- [Key](https://tactileui.dev/parts/key): Every button, and every link that acts like one: a cap on a skirt that drops below the plate when pressed.
- [Hover card](https://tactileui.dev/parts/hover-card): A preview that hangs from a link when the pointer rests on it or the keyboard reaches it. The popover’s card and leader, opened by a short delay and put away by leaving.
- [Kbd](https://tactileui.dev/parts/kbd): The key to press, drawn as the key: a small cap on a skirt with a dish worked into its top. Shortcuts come as combos and follow the platform, so ⌘ K on a Mac is Ctrl K elsewhere.
