Skip to main content
Gremorie

Tooltip

Short non-essential context shown on hover and keyboard focus. Built on Radix Tooltip with a built-in arrow.

Overview

Tooltip is for non-critical supporting information: keyboard shortcuts, icon-button labels, "what does this do" hints. Always wrap your application root in a single TooltipProvider so every tooltip shares a delay timer and they don't pop in and out of sync.

Tooltips are not for critical information. Touch users may not be able to trigger them; keyboard users only see one while the trigger holds focus. If the user must read it, render it visibly in the layout. For rich previews, use HoverCard. For interactive content, use Popover.

The TooltipContent renders its own arrow automatically.

Preview

Installation

bash npx gremorie@latest add rx-tooltip
bash pnpm dlx gremorie@latest add rx-tooltip
bash yarn dlx gremorie@latest add rx-tooltip
bash bunx --bun gremorie@latest add rx-tooltip

Usage

import { Button } from "@gremorie/rx-forms";
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@gremorie/rx-overlays";

export function Example() {
  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger asChild>
          <Button variant="outline">Hover me</Button>
        </TooltipTrigger>
        <TooltipContent>
          <p>Adds an item to the registry</p>
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}

Mount a single TooltipProvider at your app root so every tooltip shares the same timing:

// app/layout.tsx
import { TooltipProvider } from '@gremorie/rx-overlays';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <TooltipProvider delayDuration={200}>{children}</TooltipProvider>
      </body>
    </html>
  );
}

Angular edition planned for Phase 5h. Star the repo to track progress.

API

<TooltipProvider>

PropTypeDefaultDescription
delayDurationnumber0Default delay in milliseconds before tooltips open.
skipDelayDurationnumber300Time the user has after closing one tooltip to open another without delay.
disableHoverableContentbooleanfalseWhen true, tooltips close as soon as the pointer leaves the trigger.

Mount once at the application root. All tooltips share its timers.

<Tooltip>

Extends Radix Tooltip.Root. Notable props:

PropTypeDefaultDescription
openboolean-Controlled open state.
defaultOpenbooleanfalseInitial open state when uncontrolled.
onOpenChange(open: boolean) => void-Fired when open state changes.
delayDurationnumberinherits from providerPer-tooltip override of the delay.

<TooltipTrigger>

Extends Radix Tooltip.Trigger. Pair with asChild to forward styles to a Button or any focusable element.

<TooltipContent>

PropTypeDefaultDescription
sideOffsetnumber0Pixel gap between trigger and content.
side"top" | "right" | "bottom" | "left""top"Preferred side; flips automatically when there is no room.
align"start" | "center" | "end""center"Alignment relative to the trigger axis.

Wrapped in a Radix Portal. The arrow indicator is included automatically.

Composition

  1. <TooltipProvider> at the app root sets the global delay.
  2. <Tooltip> owns the open state for one tooltip instance.
  3. <TooltipTrigger asChild> wraps a focusable element (button, link, icon button).
  4. <TooltipContent> mounts via Portal with the arrow and the text.

Variations

Icon button label

The most common use. Pairs with the accessibility rule that every icon-only button needs a visible label affordance.

<Tooltip>
  <TooltipTrigger asChild>
    <Button variant="ghost" size="icon" aria-label="Copy link">
      <CopyIcon />
    </Button>
  </TooltipTrigger>
  <TooltipContent>Copy link</TooltipContent>
</Tooltip>

Keyboard shortcut hint

Pair with Kbd to surface shortcuts on dense toolbars.

<Tooltip>
  <TooltipTrigger asChild>
    <Button variant="ghost" size="icon" aria-label="Save">
      <SaveIcon />
    </Button>
  </TooltipTrigger>
  <TooltipContent>
    Save <Kbd className="ml-1">⌘S</Kbd>
  </TooltipContent>
</Tooltip>

Custom side and offset

Place tooltips above a row to avoid covering the next row.

<Tooltip>
  <TooltipTrigger asChild>
    <Button variant="ghost" size="icon" aria-label="Delete">
      <Trash2Icon />
    </Button>
  </TooltipTrigger>
  <TooltipContent side="top" sideOffset={6}>
    Delete row
  </TooltipContent>
</Tooltip>

Accessibility

  • Provider required: TooltipProvider is mandatory at the root; without it Radix throws.
  • Trigger: pointer hover and keyboard focus both open the tooltip.
  • Keyboard: focusing the trigger opens it; blurring closes; Esc closes when open.
  • Not a substitute for visible labels: icon-only buttons must also carry an aria-label. The tooltip is the visual hint; aria-label is the screen-reader name.
  • aria-describedby: linked automatically between trigger and content.
  • Touch: tooltips do not appear on touch by design. Keep their content non-critical.
  • Reduced motion: open/close animations honor prefers-reduced-motion.
  • Hover Card - hover-only rich preview for non-critical content.
  • Popover - click-driven, interactive overlay.
  • Kbd - keyboard shortcut chip, common inside tooltips.
  • Button - the most common tooltip trigger.

On this page