Skip to content
LuoForge/Tungsten
Components/Tooltip·

Tooltip

since v0.4.0

Tooltip root — pairs with TooltipTrigger and TooltipContent.

Wraps @radix-ui/react-tooltip (per ADR-0001) — Radix owns the focus,

dismiss, hover/blur timing, and portal semantics; we own class output and

the public API. Each <Tooltip> instance includes its own Provider so

consumers don't need to wire one at the app root.

Install

Add the package and import the component.

pnpm add @hey-mike/tungsten
pnpm add @hey-mike/tungsten
import { Tooltip } from '@hey-mike/tungsten';
import { Tooltip } from '@hey-mike/tungsten';

Preview

Same fixtures used by the visual-regression suite.

Usage

apps/docs/app/snapshots/tooltip/page.tsx

import { Tooltip, TooltipTrigger, TooltipContent } from '@hey-mike/tungsten';
import { VariantGrid } from '../_components/VariantGrid';
import { HeroSpecimen } from '../_components/HeroSpecimen';

export default function TooltipSnapshot() {
  return (
    <VariantGrid
      title="Tooltip"
      // Gallery thumbnail: a static, non-portaled mock of the open tooltip. The
      // real Tooltip portals to document.body, which escapes the hidden hero
      // wrapper (it would leak a stray bubble onto the detail page) and positions
      // nondeterministically inside the 160px iframe. The variants below stay
      // closed — the interactive preview reveals the real tooltip on hover.
      hero={
        <HeroSpecimen className="max-w-[180px]">
          <div className="flex flex-col items-center gap-1.5">
            <span className="bg-ink-1 text-on-ink rounded-md px-2.5 py-1.5 text-xs">
              Helpful description
            </span>
            <button
              type="button"
              className="border-stroke text-ink-2 rounded-md border px-2.5 py-1 text-xs"
            >
              Hover me
            </button>
          </div>
        </HeroSpecimen>
      }
      variants={[
        {
          label: 'default',
          node: (
            <Tooltip>
              <TooltipTrigger>
                <button type="button">Hover me</button>
              </TooltipTrigger>
              <TooltipContent>Helpful description text</TooltipContent>
            </Tooltip>
          ),
        },
        {
          label: 'with kbd',
          node: (
            <Tooltip>
              <TooltipTrigger>
                <button type="button">Open palette</button>
              </TooltipTrigger>
              <TooltipContent kbd="⌘K">Command palette</TooltipContent>
            </Tooltip>
          ),
        },
        {
          label: 'side right',
          node: (
            <Tooltip>
              <TooltipTrigger>
                <button type="button">Right</button>
              </TooltipTrigger>
              <TooltipContent side="right">Appears on the right</TooltipContent>
            </Tooltip>
          ),
        },
        {
          label: 'side bottom',
          node: (
            <Tooltip>
              <TooltipTrigger>
                <button type="button">Bottom</button>
              </TooltipTrigger>
              <TooltipContent side="bottom">Appears below</TooltipContent>
            </Tooltip>
          ),
        },
      ]}
    />
  );
}
import { Tooltip, TooltipTrigger, TooltipContent } from '@hey-mike/tungsten';
import { VariantGrid } from '../_components/VariantGrid';
import { HeroSpecimen } from '../_components/HeroSpecimen';

export default function TooltipSnapshot() {
  return (
    <VariantGrid
      title="Tooltip"
      // Gallery thumbnail: a static, non-portaled mock of the open tooltip. The
      // real Tooltip portals to document.body, which escapes the hidden hero
      // wrapper (it would leak a stray bubble onto the detail page) and positions
      // nondeterministically inside the 160px iframe. The variants below stay
      // closed — the interactive preview reveals the real tooltip on hover.
      hero={
        <HeroSpecimen className="max-w-[180px]">
          <div className="flex flex-col items-center gap-1.5">
            <span className="bg-ink-1 text-on-ink rounded-md px-2.5 py-1.5 text-xs">
              Helpful description
            </span>
            <button
              type="button"
              className="border-stroke text-ink-2 rounded-md border px-2.5 py-1 text-xs"
            >
              Hover me
            </button>
          </div>
        </HeroSpecimen>
      }
      variants={[
        {
          label: 'default',
          node: (
            <Tooltip>
              <TooltipTrigger>
                <button type="button">Hover me</button>
              </TooltipTrigger>
              <TooltipContent>Helpful description text</TooltipContent>
            </Tooltip>
          ),
        },
        {
          label: 'with kbd',
          node: (
            <Tooltip>
              <TooltipTrigger>
                <button type="button">Open palette</button>
              </TooltipTrigger>
              <TooltipContent kbd="⌘K">Command palette</TooltipContent>
            </Tooltip>
          ),
        },
        {
          label: 'side right',
          node: (
            <Tooltip>
              <TooltipTrigger>
                <button type="button">Right</button>
              </TooltipTrigger>
              <TooltipContent side="right">Appears on the right</TooltipContent>
            </Tooltip>
          ),
        },
        {
          label: 'side bottom',
          node: (
            <Tooltip>
              <TooltipTrigger>
                <button type="button">Bottom</button>
              </TooltipTrigger>
              <TooltipContent side="bottom">Appears below</TooltipContent>
            </Tooltip>
          ),
        },
      ]}
    />
  );
}

Props

Surface specific to <Tooltip />.

PropTypeDefaultDescription
defaultOpenbooleanfalseRender the content open on mount. Useful for visual snapshots. Uncontrolled mode.
openbooleanControlled open state. Pair with onOpenChange.
onOpenChange((open: boolean) => void)Fires whenever Radix wants to open or close the tooltip.
delayDurationnumber200Hover-intent delay before opening, in ms. Forwarded to Radix's Provider + Root. Defaults to 200.
skipDelayDurationnumberWindow after a tooltip closes during which the next opens instantly, in ms. Forwarded to Radix's Provider. Defaults to Radix's 300.

Sub-components

Composition slots re-exported from the same module.

TooltipTrigger

PropTypeDefaultDescription
children*ReactNodeA single focusable element (e.g. <button>, <a href>). Radix forwards its trigger props onto this element via asChild, so it must be a single element that accepts a ref and renders a real, focusable DOM node — not plain text or a fragment. This is what makes the tooltip keyboard- and screen-reader-accessible.

TooltipContent

PropTypeDefaultDescription
side"top" | "right" | "bottom" | "left"topWhich side of the trigger the tooltip appears on. Forwarded to Radix's positioner.
kbdstringOptional keyboard shortcut rendered as a mono-caps chip beside the label.

Source