---
title: Tooltip
description: A composable tooltip component for displaying contextual information on hover or focus with full accessibility support.
---

```tsx
'use client';

import { useState } from 'react';
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@/ui/Tooltip';
import { Clickable } from '@/ui/Clickable';

export function TooltipDemo() {
  const [clickTooltipOpen, setClickTooltipOpen] = useState(false);

  return (
    <div className="flex flex-col gap-24 h-300">
      <TooltipProvider>
        DARK MODE
        <div className="flex gap-48 items-center">
          <Tooltip>
            <TooltipTrigger className="underline decoration-dashed cursor-help">
              Hover me
            </TooltipTrigger>
            <TooltipContent>This is a helpful tooltip</TooltipContent>
          </Tooltip>

          <Tooltip open={clickTooltipOpen}>
            <TooltipTrigger
              render={
                <Clickable
                  className="rounded-lg border-2 border-dashed border-gray-300 p-6 text-center hover:border-gray-400 hover:bg-gray-50"
                  onClick={() => setClickTooltipOpen(!clickTooltipOpen)}
                >
                  Click me
                </Clickable>
              }
            ></TooltipTrigger>
            <TooltipContent>This tooltip opens on click</TooltipContent>
          </Tooltip>

          {/* Always open */}
          <Tooltip open>
            <TooltipTrigger className="underline decoration-dashed cursor-help">
              Always open
            </TooltipTrigger>
            <TooltipContent>This tooltip is always open</TooltipContent>
          </Tooltip>
        </div>
        LIGHT MODE
        <div className="flex gap-48 items-center">
          <Tooltip>
            <TooltipTrigger className="underline decoration-dashed cursor-help">
              Hover me
            </TooltipTrigger>
            <TooltipContent theme="light">This is a helpful tooltip</TooltipContent>
          </Tooltip>

          <Tooltip open={clickTooltipOpen}>
            <TooltipTrigger
              render={
                <Clickable
                  className="rounded-lg border-2 border-dashed border-gray-300 p-6 text-center hover:border-gray-400 hover:bg-gray-50"
                  onClick={() => setClickTooltipOpen(!clickTooltipOpen)}
                >
                  Click me
                </Clickable>
              }
            ></TooltipTrigger>
            <TooltipContent theme="light">This tooltip opens on click</TooltipContent>
          </Tooltip>

          {/* Always open */}
          <Tooltip open>
            <TooltipTrigger className="underline decoration-dashed cursor-help">
              Always open
            </TooltipTrigger>
            <TooltipContent theme="light">This tooltip is always open</TooltipContent>
          </Tooltip>
        </div>
        POSITIONS
        <div className="flex gap-48 items-center">
          <Tooltip>
            <TooltipTrigger className="underline decoration-dashed cursor-help">
              Hover me
            </TooltipTrigger>
            <TooltipContent side="top">This tooltip is on the top</TooltipContent>
            <TooltipContent side="bottom">This tooltip is on the bottom</TooltipContent>
            <TooltipContent side="right">This tooltip is on the right</TooltipContent>
            <TooltipContent side="left">This tooltip is on the left</TooltipContent>
          </Tooltip>
        </div>
      </TooltipProvider>
    </div>
  );
}
```

## Usage

```tsx showLineNumbers
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@clubmed/trident-ui';

export function Component() {
  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger className="underline decoration-dashed cursor-help">
          Hover me
        </TooltipTrigger>
        <TooltipContent>This is a helpful tooltip</TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}
```

### With Button

```tsx showLineNumbers
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@clubmed/trident-ui';
import { Button } from '@clubmed/trident-ui';

export function Component() {
  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger asChild>
          <Button variant="circle" icon="InfoCircle" size="small">
            <span className="sr-only">More information</span>
          </Button>
        </TooltipTrigger>
        <TooltipContent>Click for more details</TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}
```

### With Delay

```tsx showLineNumbers
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@clubmed/trident-ui';

export function Component() {
  return (
    <TooltipProvider delay={600}>
      <Tooltip>
        <TooltipTrigger>Hover me</TooltipTrigger>
        <TooltipContent>Appears after 600ms</TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}
```

### Rich Content

```tsx showLineNumbers
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@clubmed/trident-ui';

export function Component() {
  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger>Keyboard shortcut</TooltipTrigger>
        <TooltipContent>
          <div className="flex items-center gap-8">
            <span>Save document</span>
            <kbd
              data-slot="kbd"
              className="bg-background text-foreground px-6 py-2 rounded text-xs font-mono"
            >
              ⌘S
            </kbd>
          </div>
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}
```

### In Forms

```tsx showLineNumbers
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@clubmed/trident-ui';

export function Component() {
  return (
    <TooltipProvider>
      <form>
        <div className="flex items-center gap-8">
          <label htmlFor="username">Username</label>
          <Tooltip>
            <TooltipTrigger>ⓘ</TooltipTrigger>
            <TooltipContent>Username must be 3-20 characters</TooltipContent>
          </Tooltip>
        </div>
        <input id="username" type="text" />
      </form>
    </TooltipProvider>
  );
}
```

### Light Theme

```tsx showLineNumbers
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@clubmed/trident-ui';

export function Component() {
  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger className="underline decoration-dashed cursor-help">
          Hover me
        </TooltipTrigger>
        <TooltipContent theme="light">Light themed tooltip</TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}
```

## API Reference

### TooltipProvider

Wraps tooltip instances and provides shared configuration.

| Prop       | Type        | Default     | Description                                      |
| ---------- | ----------- | ----------- | ------------------------------------------------ |
| `delay`    | `number`    | `0`         | Delay in milliseconds before tooltip appears     |
| `children` | `ReactNode` | `undefined` | Tooltip components                               |

### Tooltip

The root tooltip component that manages state.

| Prop           | Type                         | Default     | Description                         |
| -------------- | ---------------------------- | ----------- | ----------------------------------- |
| `open`         | `boolean`                    | `undefined` | Controlled open state               |
| `defaultOpen`  | `boolean`                    | `false`     | Initial open state                  |
| `onOpenChange` | `(open: boolean) => void`    | `undefined` | Callback when open state changes    |
| `children`     | `ReactNode`                  | `undefined` | Trigger and content components      |

### TooltipTrigger

The element that triggers the tooltip display.

| Prop       | Type                           | Default     | Description                                    |
| ---------- | ------------------------------ | ----------- | ---------------------------------------------- |
| `asChild`  | `boolean`                      | `false`     | Merge props onto child instead of wrapping     |
| `children` | `ReactNode`                    | `undefined` | Trigger element                                |
| `...props` | `button` props                 | -           | Standard button attributes for the trigger     |

### TooltipContent

The popup content with positioning and styling.

| Prop          | Type                                         | Default     | Description                             |
| ------------- | -------------------------------------------- | ----------- | --------------------------------------- |
| `side`        | `'top' \| 'right' \| 'bottom' \| 'left'`     | `'top'`     | Placement side relative to trigger      |
| `sideOffset`  | `number`                                     | `4`         | Distance from trigger in pixels         |
| `align`       | `'start' \| 'center' \| 'end'`               | `'center'`  | Alignment relative to trigger           |
| `alignOffset` | `number`                                     | `0`         | Offset along the alignment axis (px)    |
| `theme`       | `'dark' \| 'light'`                          | `'dark'`    | Color theme (dark or light)             |
| `className`   | `string`                                     | `undefined` | Additional CSS classes                  |
| `children`    | `ReactNode`                                  | `undefined` | Tooltip content                         |

## Positioning

The tooltip can be positioned on any side of the trigger with various alignment options:

```tsx
// Position on different sides
<TooltipContent side="top">Top</TooltipContent>
<TooltipContent side="right">Right</TooltipContent>
<TooltipContent side="bottom">Bottom</TooltipContent>
<TooltipContent side="left">Left</TooltipContent>

// Align relative to trigger
<TooltipContent align="start">Start aligned</TooltipContent>
<TooltipContent align="center">Center aligned</TooltipContent>
<TooltipContent align="end">End aligned</TooltipContent>

// Custom offsets
<TooltipContent sideOffset={20} alignOffset={10}>
  Custom offset
</TooltipContent>
```

## Styling

The tooltip comes with default styling using Tailwind classes. Customize by adding your own classes:

```tsx
<TooltipContent className="bg-turquoise text-white">
  Custom colored tooltip
</TooltipContent>
```

### Default Styles

**Dark theme (default):**
- Background: `bg-black`
- Text: `text-white`

**Light theme:**
- Background: `bg-lightGrey`
- Text: `text-black`

**Shared styles:**
- Border radius: `rounded-8`
- Padding: `p-8`
- Max width: `max-w-xs`
- Font size: `text-xs`
- Z-index: `z-50`
- Includes animated arrow pointer that matches the theme

## Accessibility

The Tooltip component follows WAI-ARIA guidelines:

- ✅ Keyboard navigation support (focus/blur triggers)
- ✅ Screen reader support
- ✅ Proper ARIA attributes
- ✅ Automatic ID management

### Keyboard Interactions

- **Tab** - Focus trigger element, showing tooltip
- **Shift+Tab** - Move focus away, hiding tooltip

### Best Practices

1. **Keep content concise** - Tooltips should be brief (under 50 characters when possible)
2. **Don't hide critical information** - Tooltips are supplementary; critical info should be visible
3. **Make triggers keyboard accessible** - Use focusable elements (buttons, links, etc.)
4. **Avoid interactive content** - Don't put buttons or links in tooltips (use Popover instead)
5. **Provide appropriate delays** - 200-600ms is recommended for better UX

```tsx
// Good: Accessible trigger
<TooltipTrigger asChild>
  <button aria-label="More information">
    <Icon name="InfoCircle" />
  </button>
</TooltipTrigger>

// Bad: Non-focusable trigger
<TooltipTrigger>
  <div>Hover me</div>
</TooltipTrigger>
```

## Notes

- The tooltip uses Base UI's `@base-ui/react/tooltip` primitives for reliable positioning and accessibility
- Tooltips are rendered in a portal to prevent stacking context issues
- Animations are CSS-based for optimal performance
- Multiple tooltips can share the same `TooltipProvider` for consistent delay settings
- The arrow automatically adjusts position based on the tooltip's placement
