npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@choice-ui/tooltip

v0.0.9

Published

A tooltip component that displays additional information on hover or focus

Readme

Tooltip

A lightweight floating component for displaying helpful information on hover or focus. Supports multiple positioning options, keyboard shortcuts display, and delay groups for smooth user experience.

Import

import { Tooltip, TooltipProvider } from "@choice-ui/react"

Features

  • Two API styles: simple prop-based and compound component
  • Multiple positioning options (12 placements)
  • Visual variants (default and light)
  • Keyboard shortcut display support
  • Delay groups for smooth multi-tooltip experiences
  • Configurable offset and arrow display
  • Proper accessibility with ARIA support
  • Optimized hover behavior to prevent flickering

Usage

Simple API (Recommended)

The simple API uses the content prop for quick tooltip implementation:

{
  /* Basic tooltip */
}
;<Tooltip content="Basic tooltip">
  <Button>Basic Tooltip</Button>
</Tooltip>

{
  /* With keyboard shortcut */
}
;<Tooltip
  content="Save file"
  shortcut={{
    modifier: ["command"],
    keys: "S",
  }}
>
  <Button>Save</Button>
</Tooltip>

{
  /* Without arrow */
}
;<Tooltip
  content="Tooltip without arrow"
  withArrow={false}
>
  <Button>No Arrow</Button>
</Tooltip>

{
  /* Disabled tooltip */
}
;<Tooltip
  content="This tooltip is disabled"
  disabled={true}
>
  <Button>Disabled</Button>
</Tooltip>

Compound Component API

For more control over tooltip structure:

<Tooltip>
  <TooltipTrigger>
    <Button>Hover me</Button>
  </TooltipTrigger>
  <TooltipContent>This is a tooltip</TooltipContent>
</Tooltip>

Variants

{
  /* Default variant (dark) */
}
;<Tooltip
  content="Default style"
  variant="default"
>
  <Button>Default</Button>
</Tooltip>

{
  /* Light variant */
}
;<Tooltip
  content="Light style"
  variant="light"
>
  <Button>Light</Button>
</Tooltip>

Custom Offset

{
  /* Large offset */
}
;<Tooltip
  content="Large offset"
  offset={20}
>
  <Button>Large Offset</Button>
</Tooltip>

{
  /* Small offset */
}
;<Tooltip
  content="Small offset"
  offset={2}
>
  <Button>Small Offset</Button>
</Tooltip>

Placements

All 12 Floating UI placements are supported:

{/* Top placements */}
<Tooltip placement="top-start">
  <TooltipTrigger><Button>Top Start</Button></TooltipTrigger>
  <TooltipContent>Top start placement</TooltipContent>
</Tooltip>

<Tooltip placement="top">
  <TooltipTrigger><Button>Top</Button></TooltipTrigger>
  <TooltipContent>Top placement</TooltipContent>
</Tooltip>

<Tooltip placement="top-end">
  <TooltipTrigger><Button>Top End</Button></TooltipTrigger>
  <TooltipContent>Top end placement</TooltipContent>
</Tooltip>

{/* Bottom placements */}
<Tooltip placement="bottom-start">
  <TooltipTrigger><Button>Bottom Start</Button></TooltipTrigger>
  <TooltipContent>Bottom start placement</TooltipContent>
</Tooltip>

<Tooltip placement="bottom">
  <TooltipTrigger><Button>Bottom</Button></TooltipTrigger>
  <TooltipContent>Bottom placement</TooltipContent>
</Tooltip>

<Tooltip placement="bottom-end">
  <TooltipTrigger><Button>Bottom End</Button></TooltipTrigger>
  <TooltipContent>Bottom end placement</TooltipContent>
</Tooltip>

{/* Left placements */}
<Tooltip placement="left-start">
  <TooltipTrigger><Button>Left Start</Button></TooltipTrigger>
  <TooltipContent>Left start placement</TooltipContent>
</Tooltip>

<Tooltip placement="left">
  <TooltipTrigger><Button>Left</Button></TooltipTrigger>
  <TooltipContent>Left placement</TooltipContent>
</Tooltip>

<Tooltip placement="left-end">
  <TooltipTrigger><Button>Left End</Button></TooltipTrigger>
  <TooltipContent>Left end placement</TooltipContent>
</Tooltip>

{/* Right placements */}
<Tooltip placement="right-start">
  <TooltipTrigger><Button>Right Start</Button></TooltipTrigger>
  <TooltipContent>Right start placement</TooltipContent>
</Tooltip>

<Tooltip placement="right">
  <TooltipTrigger><Button>Right</Button></TooltipTrigger>
  <TooltipContent>Right placement</TooltipContent>
</Tooltip>

<Tooltip placement="right-end">
  <TooltipTrigger><Button>Right End</Button></TooltipTrigger>
  <TooltipContent>Right end placement</TooltipContent>
</Tooltip>

Delay Groups

Use TooltipProvider to create smooth tooltip experiences across multiple elements:

<TooltipProvider
  delay={{
    open: 400,
    close: 200,
  }}
>
  <div className="flex gap-4">
    <Tooltip>
      <TooltipTrigger>
        <Button>First</Button>
      </TooltipTrigger>
      <TooltipContent>First tooltip - 400ms delay initially</TooltipContent>
    </Tooltip>

    <Tooltip>
      <TooltipTrigger>
        <Button>Second</Button>
      </TooltipTrigger>
      <TooltipContent>Second tooltip - instant when moving from first</TooltipContent>
    </Tooltip>

    <Tooltip>
      <TooltipTrigger>
        <Button>Third</Button>
      </TooltipTrigger>
      <TooltipContent>Third tooltip - instant when moving from others</TooltipContent>
    </Tooltip>
  </div>
</TooltipProvider>

Keyboard Shortcuts

Display keyboard shortcuts in tooltips:

{
  /* Command + K */
}
;<Tooltip
  content="Save file"
  shortcut={{ modifier: ["command"], keys: "K" }}
>
  <Button>Command + K</Button>
</Tooltip>

{
  /* Ctrl + A */
}
;<Tooltip
  content="Select all"
  shortcut={{ modifier: ["ctrl"], keys: "A" }}
>
  <Button>Ctrl + A</Button>
</Tooltip>

{
  /* Shift + A */
}
;<Tooltip
  content="Shift shortcut"
  shortcut={{ modifier: ["shift"], keys: "A" }}
>
  <Button>Shift + A</Button>
</Tooltip>

All Variants with Placements

<TooltipProvider delay={{ open: 400, close: 200 }}>
  <div className="grid grid-cols-4 gap-4">
    {["default", "light"].map((variant) =>
      ["right", "left", "top", "bottom"].map((placement) => (
        <Tooltip
          key={`${placement}-${variant}`}
          placement={placement as Placement}
        >
          <TooltipTrigger>
            <Button variant="secondary">
              {placement} / {variant}
            </Button>
          </TooltipTrigger>
          <TooltipContent variant={variant as "default" | "light"}>
            {placement} / {variant}
          </TooltipContent>
        </Tooltip>
      )),
    )}
  </div>
</TooltipProvider>

Props

Tooltip (Simple API)

interface TooltipProps {
  /** Child elements (typically the trigger) */
  children?: React.ReactNode

  /** Additional CSS classes */
  className?: string

  /** Tooltip content (enables simple API) */
  content?: React.ReactNode

  /** Disable the tooltip */
  disabled?: boolean

  /** Distance from trigger element */
  offset?: number

  /** Open state change callback */
  onOpenChange?: (open: boolean) => void

  /** Controlled open state */
  open?: boolean

  /** Tooltip placement */
  placement?: Placement

  /** Portal container ID */
  portalId?: string

  /** Keyboard shortcut display */
  shortcut?: {
    keys?: ReactNode
    modifier?: KbdKey[]
  }

  /** Visual variant */
  variant?: "default" | "light"

  /** Show/hide arrow */
  withArrow?: boolean
}
  • Defaults:
    • disabled: false
    • offset: 8
    • variant: "default"
    • withArrow: true
    • portalId: "floating-tooltip-root"

TooltipProvider

interface TooltipProviderProps {
  children: React.ReactNode
  delay?: {
    open?: number
    close?: number
  }
}

TooltipTrigger

Compound component trigger - accepts any React element as children.

TooltipContent

interface TooltipContentProps {
  children: React.ReactNode
  className?: string
  variant?: "default" | "light"
  withArrow?: boolean
  portalId?: string
}

Components

Tooltip

The main tooltip component that supports both simple and compound APIs.

TooltipProvider

Wraps multiple tooltips to enable delay groups and smooth transitions.

TooltipTrigger

The trigger element for compound component usage.

TooltipContent

The content container for compound component usage.

Styling

  • Uses Tailwind CSS via tailwind-variants
  • Two variants: default (dark) and light
  • Customizable with className prop
  • Arrow styling matches content variant
  • Smooth fade transitions
  • Responsive positioning

Best Practices

Usage Guidelines

  • Use for helpful, non-essential information
  • Keep content concise and scannable
  • Don't use for critical information users must see
  • Consider delay groups for multiple related tooltips
  • Include keyboard shortcuts when relevant

Content Guidelines

  • Write clear, helpful descriptions
  • Use sentence case for consistency
  • Keep text brief (ideally under 10 words)
  • Don't repeat information already visible on screen

Accessibility

  • Tooltips appear on both hover and focus
  • Proper ARIA attributes for screen readers
  • Keyboard navigation support (ESC to close)
  • Content is announced to assistive technologies
  • Focus remains on trigger element

Performance

  • Optimized hover behavior prevents flickering
  • Lazy loading of tooltip content
  • Efficient positioning calculations
  • Memory management for delay groups

Examples

Icon Button with Tooltip

<Tooltip content="Delete item">
  <IconButton variant="destructive">
    <TrashIcon />
  </IconButton>
</Tooltip>

Action Button with Shortcut

<Tooltip
  content="Create new document"
  shortcut={{ modifier: ["command"], keys: "N" }}
>
  <Button>
    <PlusIcon />
    New
  </Button>
</Tooltip>

Disabled Button with Explanation

<Tooltip
  content="Save is disabled until all required fields are completed"
  variant="light"
>
  <Button disabled>Save</Button>
</Tooltip>

Complex Tooltip with Compound API

<Tooltip placement="bottom">
  <TooltipTrigger>
    <div className="rounded border p-2">Complex trigger element</div>
  </TooltipTrigger>
  <TooltipContent
    variant="light"
    className="max-w-xs"
  >
    <div className="space-y-1">
      <div className="font-strong">Complex Content</div>
      <div className="text-body-small">
        This tooltip contains multiple lines and rich formatting.
      </div>
    </div>
  </TooltipContent>
</Tooltip>

Toolbar with Delay Group

<TooltipProvider delay={{ open: 500, close: 100 }}>
  <div className="flex items-center gap-1 rounded border p-2">
    <Tooltip content="Bold">
      <IconButton>
        <BoldIcon />
      </IconButton>
    </Tooltip>
    <Tooltip content="Italic">
      <IconButton>
        <ItalicIcon />
      </IconButton>
    </Tooltip>
    <Tooltip content="Underline">
      <IconButton>
        <UnderlineIcon />
      </IconButton>
    </Tooltip>
  </div>
</TooltipProvider>

Notes

  • Simple API (with content prop) is recommended for most use cases
  • Compound API provides more control over tooltip structure
  • Delay groups create smooth experiences when users move between tooltips quickly
  • Keyboard shortcuts are automatically formatted using the Kbd component
  • Tooltips are portal-rendered to avoid z-index issues
  • Both APIs support the same positioning and styling options
  • TooltipProvider manages timing and prevents tooltip flicker during rapid movements