---
title: Tooltip
description: "A popup that displays information related to an element on hover or focus."
---

```tsx
import { Button } from '@/components/ui/button';
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/tooltip';

export default function TooltipDemo() {
  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger render={<Button variant="outline" />}>
          Hover me
        </TooltipTrigger>
        <TooltipContent>Add to library</TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}
```

## Install

```bash
npx shadcn@latest add @madeui/tooltip
```

## Usage

```tsx
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/tooltip';

// Wrap your app (or a subtree) in <TooltipProvider> once.
```

## Composition

```tsx
<TooltipProvider>
  <Tooltip>
    <TooltipTrigger />
    <TooltipContent />
  </Tooltip>
</TooltipProvider>
```

## Sides

```tsx
import * as stylex from '@stylexjs/stylex';

import { space } from '@/lib/constants.stylex';

import { Button } from '@/components/ui/button';
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/tooltip';

const sides = ['top', 'right', 'bottom', 'left'] as const;

export default function TooltipSides() {
  return (
    <TooltipProvider>
      <div {...stylex.props(styles.row)}>
        {sides.map((side) => (
          <Tooltip key={side}>
            <TooltipTrigger render={<Button variant="outline" />}>
              {side}
            </TooltipTrigger>
            <TooltipContent side={side}>Tooltip on {side}</TooltipContent>
          </Tooltip>
        ))}
      </div>
    </TooltipProvider>
  );
}

const styles = stylex.create({
  row: {
    alignItems: 'center',
    display: 'flex',
    flexWrap: 'wrap',
    gap: space.s2,
  },
});
```

## Disabled button

Native `disabled` buttons don't fire pointer events, so the tooltip trigger has to be a wrapping element instead of the button itself.

```tsx
import * as stylex from '@stylexjs/stylex';

import { Button } from '@/components/ui/button';
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/tooltip';

export default function TooltipDisabledButton() {
  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger render={<span {...stylex.props(styles.trigger)} />}>
          <Button variant="outline" disabled>
            Submit
          </Button>
        </TooltipTrigger>
        <TooltipContent>Complete the form to submit</TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}

const styles = stylex.create({
  // Disabled native buttons don't fire pointer events, so the tooltip
  // trigger has to be the wrapping span instead of the button itself.
  trigger: {
    display: 'inline-block',
  },
});
```

## API reference

Built on [Base UI Tooltip](https://base-ui.com/react/components/tooltip). The tables below cover the props this library adds or changes — every other prop is forwarded to the underlying Base UI part; see the [Base UI Tooltip API reference](https://base-ui.com/react/components/tooltip#api-reference) for the full list.

### TooltipContent

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` |  |
| `sideOffset` | `number` | `4` | Distance from the trigger, in px. |
| `align` | `'start' \| 'center' \| 'end'` | `'center'` |  |
| `alignOffset` | `number` | `0` |  |
| `style` | `StyleXStyles` | — | StyleX styles merged last — always win over the component's own styles. |

### TooltipProvider

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `delay` | `number` | `0` | Hover delay before opening, in ms. Instant by default. |

`Tooltip` (Root) and `TooltipTrigger` are Base UI parts re-exported unstyled; `TooltipTrigger` accepts `render`.
