# Tooltip

> Package `@umriss-ui/core`, version 0.40.0. Demo page: <https://romanhaendler.github.io/umriss-ui/core/tooltip/>. Every page in one line: [llms.txt](https://romanhaendler.github.io/umriss-ui/core/llms.txt); every page in full: [llms-full.txt](https://romanhaendler.github.io/umriss-ui/core/llms-full.txt).

A sentence of explanation that appears while the pointer rests on an element or the keyboard focus is on it (also called a hint). Reach for it to explain an abbreviation or a control; an icon button names itself as an [IconButton](https://romanhaendler.github.io/umriss-ui/core/iconbutton/).

```ts
import { Tooltip } from "@umriss-ui/core";
```

Demo page: https://romanhaendler.github.io/umriss-ui/core/tooltip/

It wraps exactly one element that can take focus and a ref; on text, give a `span` a `tabIndex` of 0.

Anything that stands only in a tooltip is lost on a touch screen. Keep it to a sentence that repeats or explains what is already there.

It shows for keyboard focus, not for the focus a click leaves behind, and a tooltip that repeats its element's `aria-label` does not describe the element a second time.

## Examples

### A tooltip

Wrap one focusable element; the `content` appears on pointer contact and on keyboard focus alike.

```tsx
import { Button, Tooltip } from "@umriss-ui/core";

export default function ATooltip() {
  return (
    <Tooltip content="Copies the board with its columns, not its cards.">
      <Button size="sm">Duplicate the board</Button>
    </Tooltip>
  );
}
```

### Delay

`delay` is 300 ms by default so a passing pointer shows nothing; set it to 0 where the reader hovers on purpose.

```tsx
import { Button, Stack, Tooltip } from "@umriss-ui/core";

export default function Delay() {
  return (
    <Stack direction="row" gap={3}>
      <Tooltip content="Appears after 300 ms.">
        <Button size="sm">Default delay</Button>
      </Tooltip>
      <Tooltip content="Appears at once." delay={0}>
        <Button size="sm">Without a delay</Button>
      </Tooltip>
    </Stack>
  );
}
```

### Explain an abbreviation

On text, make the element focusable with `tabIndex={0}` so a keyboard reader reaches the explanation too.

```tsx
import { Stack, Text, Tooltip } from "@umriss-ui/core";

/* Focusable text owes a visible focus: the library's ring, from its token. */
const STYLE = `
.abbreviation {
  text-decoration: underline dotted;
  cursor: help;
  border-radius: var(--u-radius-xs);
}
.abbreviation:focus-visible {
  outline: none;
  box-shadow: var(--u-focus-ring);
}
`;

export default function AnAbbreviation() {
  return (
    <Stack gap={1}>
      <style>{STYLE}</style>
      <Text size="xs" tone="muted">
        Checkout ·{" "}
        <Tooltip content="95th percentile: 95 of 100 requests were faster than this.">
          <span className="abbreviation" tabIndex={0}>
            p95
          </span>
        </Tooltip>{" "}
        latency
      </Text>
      <Text size="xl" mono>
        412 ms
      </Text>
    </Stack>
  );
}
```

### Show how a figure came about

The content may be built from `Text`: inside a tooltip every tone turns round and reads on the tooltip's ground.

```tsx
import { Text, Tooltip } from "@umriss-ui/core";

/* Focusable text owes a visible focus: the library's ring, from its token. */
const STYLE = `
.figure {
  cursor: help;
  border-radius: var(--u-radius-xs);
}
.figure:focus-visible {
  outline: none;
  box-shadow: var(--u-focus-ring);
}
`;

export default function ACalculation() {
  return (
    <>
      <style>{STYLE}</style>
      <Tooltip
        content={
          <>
            <Text size="xs" mono>
              3 × 12.50 € = 37.50 €
            </Text>
            <Text size="xs" tone="muted">
              Quantity × unit price
            </Text>
          </>
        }
      >
        <Text as="span" size="xl" mono className="figure" tabIndex={0}>
          37.50 €
        </Text>
      </Tooltip>
    </>
  );
}
```

## When to use something else

- The content has a link, a button or more than a sentence → Popover
- The reader must see it without hovering → Plain text beside the element

## Keyboard

| Key | Action |
|---|---|
| `Tab` | Focusing the element shows its tooltip; moving focus away hides it. |
| `Escape` | Hides the tooltip. |

## API

### `TooltipProps`

| Prop | Type | Default | Description |
|---|---|---|---|
| `content` *required* | `ReactNode` | — | Short help text; no interaction, no long content.<br>Shown in: [A tooltip](https://romanhaendler.github.io/umriss-ui/core/tooltip/#a-tooltip), [Delay](https://romanhaendler.github.io/umriss-ui/core/tooltip/#delay), [Explain an abbreviation](https://romanhaendler.github.io/umriss-ui/core/tooltip/#an-abbreviation) and 2 more |
| `children` *required* | `ReactElement<Record<string, unknown>>` | — | Exactly one element that triggers the tooltip (must accept refs). Its own ref keeps its element: the tooltip holds the same one beside it.<br>Shown in: [A tooltip](https://romanhaendler.github.io/umriss-ui/core/tooltip/#a-tooltip), [Delay](https://romanhaendler.github.io/umriss-ui/core/tooltip/#delay), [Explain an abbreviation](https://romanhaendler.github.io/umriss-ui/core/tooltip/#an-abbreviation) and 2 more |
| `delay` | `number` | `300` | Delay in ms before the tooltip appears.<br>Shown in: [Delay](https://romanhaendler.github.io/umriss-ui/core/tooltip/#delay) |

## Known limits

- No interactive content and no rich layout inside: it is read, never used.
- No placement option: it stands above its element and flips below where there is no room.

What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
