# Tooltip

> Short label on hover or focus with an optional shortcut, origin-aware motion and instant skip between tooltips.

- **Slug:** `tooltip` · **Category:** primitives · **Status:** stable
- **Import:** `import { Tooltip, TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger } from "@kura-ui/react/tooltip";`
- **Docs:** https://kuro.abstergo.fyi/components/tooltip
- **Registry item:** https://kuro.abstergo.fyi/r/tooltip.json
- **Tags:** tooltip, hint, label, hover, overlay

## Install

```bash
# shadcn registry (copies source into your project)
npx shadcn@latest add https://kuro.abstergo.fyi/r/tooltip.json
# Kura CLI (same, plus dependency resolution and --json output)
npx @kura-ui/cli add tooltip
# npm package
npm install @kura-ui/react
```

## When to use

- Name an icon-only control or reveal its shortcut.
- Brief supplementary hints (a few words).

## When not to use

- Interactive or rich content (links, buttons, forms) — use popover.
- Essential information — it is invisible on touch devices; put it in the UI.
- Labelling icon buttons — icon-button already includes a tooltip.

## Props

| Prop | Type | Default | Required | Description |
| --- | --- | --- | --- | --- |
| `content` | `React.ReactNode` | — | yes | The label. Keep it to a few words. |
| `children` | `React.ReactElement` | — | yes | The trigger: one focusable element that accepts a ref. |
| `shortcut` | `readonly KeyName[]` | — | no | Keys shown after the label, e.g. ["mod", "enter"]. |
| `side` | `"top" \| "right" \| "bottom" \| "left"` | `"top"` | no | Preferred side. |
| `align` | `"start" \| "center" \| "end"` | `"center"` | no | Alignment on that side. |
| `delayDuration` | `number` | `500` | no | Hover delay in ms before opening. Inside a TooltipProvider, defaults to the provider's. |
| `disabled` | `boolean` | `false` | no | Render only the trigger. |
| `contentClassName` | `string` | — | no | Classes for the floating bubble. |

Native attributes of the root element, `className` and `ref` are passed through.

## Anatomy

- **TooltipProvider** — Optional shared provider so moving between tooltips skips the delay.
- **TooltipRoot** — Radix Root, for fully custom compositions.
- **TooltipTrigger** — Radix Trigger.
- **TooltipContent** (`data-slot="tooltip-content"`) — Styled floating bubble; accepts `shortcut`.
  - `shortcut`: `readonly KeyName[]` — Keys shown after the label.

## Accessibility

- Role: `tooltip`
- Opens on hover after a delay and immediately on keyboard focus; the trigger gets aria-describedby.
- Never the only way to reach information; not shown on touch.
- Reduced motion: Scale and travel are removed; only a fast fade remains.

| Keys | Action |
| --- | --- |
| Tab | Focus the trigger and open |
| Escape | Close |

## Notes for agents

- The child must forward refs and accept event props (Kura Button/IconButton do). Wrap plain text in a <button>.
- <Tooltip> (and IconButton) creates its own provider only when standalone; inside a <TooltipProvider> it joins it, so wrapping a toolbar in TooltipProvider makes moving between sibling tooltips instant.

## Examples

### Basic (minimal)

```tsx
import { Button } from "@kura-ui/react/button";
import { Tooltip } from "@kura-ui/react/tooltip";

export function TooltipMinimal() {
  return (
    <Tooltip content="Copy to clipboard">
      <Button variant="secondary">Hover me</Button>
    </Tooltip>
  );
}
```

### Shortcut, sides and shared provider (full)

```tsx
import { Button } from "@kura-ui/react/button";
import { Tooltip, TooltipProvider } from "@kura-ui/react/tooltip";

export function TooltipFull() {
  return (
    <TooltipProvider>
      <div className="flex items-center gap-2">
        <Tooltip content="Send message" shortcut={["mod", "enter"]} side="top">
          <Button variant="secondary" size="sm">
            Top
          </Button>
        </Tooltip>
        <Tooltip
          content="New chat"
          shortcut={["mod", "shift", "o"]}
          side="bottom"
          delayDuration={200}
        >
          <Button variant="secondary" size="sm">
            Bottom
          </Button>
        </Tooltip>
        <Tooltip content="Disabled tooltip" disabled>
          <Button variant="ghost" size="sm">
            No tooltip
          </Button>
        </Tooltip>
      </div>
    </TooltipProvider>
  );
}
```

### Editor toolbar with shared delay (composition)

Tooltip parts under one TooltipProvider, so moving across the formatting toolbar skips the open delay.

```tsx
"use client";

import { Bold, Cloud, Code, Italic, Link, PenLine, Redo2, Undo2 } from "lucide-react";
import * as React from "react";
import { Button } from "@kura-ui/react/button";
import { TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger } from "@kura-ui/react/tooltip";

const formatTools = [
  { id: "bold", label: "Bold", icon: <Bold />, shortcut: ["mod", "b"] },
  { id: "italic", label: "Italic", icon: <Italic />, shortcut: ["mod", "i"] },
  { id: "code", label: "Inline code", icon: <Code />, shortcut: ["mod", "e"] },
  { id: "link", label: "Link", icon: <Link />, shortcut: ["mod", "k"] },
] as const;

function ToolbarTip({
  label,
  shortcut,
  side = "top",
  children,
}: {
  label: string;
  shortcut?: readonly string[];
  side?: "top" | "bottom";
  children: React.ReactElement;
}) {
  return (
    <TooltipRoot>
      <TooltipTrigger asChild>{children}</TooltipTrigger>
      <TooltipContent side={side} shortcut={shortcut}>
        {label}
      </TooltipContent>
    </TooltipRoot>
  );
}

const square = "size-7 px-0";

export function TooltipEditorToolbar() {
  const [active, setActive] = React.useState<string[]>(["bold"]);
  const toggle = (id: string) =>
    setActive((a) => (a.includes(id) ? a.filter((x) => x !== id) : [...a, id]));

  return (
    <TooltipProvider delayDuration={400}>
      <div className="flex w-full max-w-xl flex-col overflow-hidden rounded-kura-xl bg-kura-surface shadow-kura-sm">
        <div
          role="toolbar"
          aria-label="Formatting"
          className="flex items-center gap-0.5 border-kura-border-subtle border-b px-2 py-1.5"
        >
          <ToolbarTip label="Undo" shortcut={["mod", "z"]}>
            <Button variant="ghost" size="sm" aria-label="Undo" className={square}>
              <Undo2 />
            </Button>
          </ToolbarTip>
          <ToolbarTip label="Redo" shortcut={["mod", "shift", "z"]}>
            <Button variant="ghost" size="sm" aria-label="Redo" className={square}>
              <Redo2 />
            </Button>
          </ToolbarTip>
          <span aria-hidden className="mx-1 h-4 w-px bg-kura-border" />
          {formatTools.map((tool) => (
            <ToolbarTip key={tool.id} label={tool.label} shortcut={tool.shortcut}>
              <Button
                variant="ghost"
                size="sm"
                aria-label={tool.label}
                aria-pressed={active.includes(tool.id)}
                onClick={() => toggle(tool.id)}
                className={`${square} aria-pressed:bg-kura-active aria-pressed:text-kura-fg`}
              >
                {tool.icon}
              </Button>
            </ToolbarTip>
          ))}
          <span aria-hidden className="mx-1 h-4 w-px bg-kura-border" />
          <ToolbarTip label="Rewrite the selection" shortcut={["mod", "j"]}>
            <Button variant="ghost" size="sm">
              <PenLine />
              Rewrite
            </Button>
          </ToolbarTip>
          <div className="ml-auto flex items-center">
            <ToolbarTip label="Saved 12:04 · version 18" side="bottom">
              <button
                type="button"
                className="inline-flex h-7 cursor-default items-center gap-1.5 rounded-kura-sm px-2 text-kura-fg-subtle text-xs outline-none focus-visible:shadow-kura-focus"
              >
                <Cloud className="size-3.5" aria-hidden />
                Saved
              </button>
            </ToolbarTip>
          </div>
        </div>
        <p className="px-4 py-3.5 text-[15px] text-kura-fg leading-relaxed">
          <strong className="font-semibold">Launch note:</strong> the new composer ships behind the{" "}
          <code className="rounded-kura-xs bg-kura-surface-sunken px-1 py-0.5 font-kura-mono text-[13px]">
            composer_v2
          </code>{" "}
          flag on Thursday, starting with 10% of workspaces.
        </p>
      </div>
    </TooltipProvider>
  );
}
```

## Dependencies

- npm: `radix-ui`
- Kura registry items: `kura-theme`, `kbd`, `kura-keys`, `utils`
- Related: `icon-button`, `popover`, `kbd`
