# Tooltip

> Positioned hint with eight placement options, arrow, and delay control. Uses `aria-describedby`.

- Available in: `@sisyphos-ui/react`, `@sisyphos-ui/vue`, `@sisyphos-ui/angular`
- Docs: https://www.sisyphosui.com/docs/components/tooltip
- WAI-ARIA pattern: [Tooltip](https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/)

## Installation

Pick the framework binding that matches your stack:

```bash
pnpm add @sisyphos-ui/react   # React 18+
pnpm add @sisyphos-ui/vue     # Vue 3+
pnpm add @sisyphos-ui/angular # Angular 17+
```

## Import

```tsx
import "@sisyphos-ui/react/styles.css";
import { Tooltip } from "@sisyphos-ui/react";
```

## Framework usage

### React 18+

```tsx
import { Tooltip, Button } from "@sisyphos-ui/react";

export const Hint = () => (
  <Tooltip content="⌘K to search">
    <Button variant="outlined">Hover me</Button>
  </Tooltip>
);
```

### Vue 3+

```vue
<script setup lang="ts">
import { Tooltip, Button } from "@sisyphos-ui/vue";
</script>

<template>
  <Tooltip content="⌘K to search">
    <Button variant="outlined">Hover me</Button>
  </Tooltip>
</template>
```

### Angular 17+

```ts
import { Component } from "@angular/core";
import { Button, TooltipDirective } from "@sisyphos-ui/angular";

@Component({
  selector: "app-hint",
  standalone: true,
  imports: [Button, TooltipDirective],
  template: `
    <span sui-tooltip="⌘K to search">
      <sui-button variant="outlined">Hover me</sui-button>
    </span>
  `,
})
export class HintComponent {}
```

## Examples

### Default

```tsx
import { Button, Tooltip } from "@sisyphos-ui/react";

export function Example() {
  return (
    <div className="flex flex-wrap items-end gap-8">
      {/* 1. Instant tooltip — openDelay=0 for keyboard hints */}
      <Tooltip content="Open command palette" placement="top" openDelay={0}>
        <Button variant="outlined">⌘K</Button>
      </Tooltip>

      {/* 2. Disabled button tooltip — wrap in a focusable span */}
      <Tooltip
        content="You need the Admin role to edit this"
        placement="bottom"
        arrow={false}
      >
        <span tabIndex={0}>
          <Button variant="outlined" disabled>
            Delete workspace
          </Button>
        </span>
      </Tooltip>

      {/* 3. Rich multi-line content with a <kbd> element */}
      <Tooltip
        placement="right"
        content={
          <div>
            <div style={{ fontWeight: 600 }}>Keyboard shortcut</div>
            <div style={{ marginTop: 4, opacity: 0.8 }}>
              Use <kbd>⌘ Enter</kbd> to submit from anywhere in the form.
            </div>
          </div>
        }
      >
        <Button variant="outlined">Rich content</Button>
      </Tooltip>
    </div>
  );
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| **content** (required) | `ReactNode` | — | Tooltip content. When falsy, the tooltip is disabled entirely. |
| **children** (required) | `ReactElement` | — | Exactly one focusable element used as the anchor. |
| placement | `"top" \| "bottom" \| "left" \| "right" \| "top-start" \| "top-end" \| "bottom-start" \| "bottom-end"` | `"top"` | Preferred placement; auto-flips to the opposite side if it doesn't fit the viewport. |
| offset | `number` | `8` | Pixel gap between the anchor and the tooltip. |
| openDelay | `number` | `200` | Milliseconds before showing on hover or focus. |
| closeDelay | `number` | `100` | Milliseconds before hiding on leave or blur. |
| arrow | `boolean` | `true` | Render an arrow pointing at the anchor. |
| open | `boolean` | — | Controlled open state; omit to stay uncontrolled. |
| onOpenChange | `(open: boolean) => void` | — | Fired whenever the open state changes. |
| disabled | `boolean` | `false` | Disable the tooltip entirely (e.g. on touch devices). |

## Keyboard interactions

- **Tab** — Focusing the trigger shows the tooltip after `openDelay`; blurring hides it after `closeDelay`.
- **Esc** — Dismisses the tooltip while it is visible.

## Accessibility notes

- The floating element renders with `role="tooltip"` and is linked to the trigger through `aria-describedby` while visible (merged with any existing `aria-describedby`).
- Shows on keyboard focus as well as hover, and hides on blur — full parity between pointer and keyboard users.
- Escape dismisses the tooltip without moving focus off the trigger.
- The arrow is `aria-hidden`; when `content` is falsy or `disabled` is set, no tooltip or ARIA wiring is rendered at all.

<!-- exports: { "Tooltip": "@sisyphos-ui/react" } -->