# Tooltip Guides

## Patterns

### Icon Hint

When to use:

- An icon or compact trigger needs a short explanation.

Composition notes:

- Keep the trigger labeled independently.
- Keep the tooltip content shorter than a popover would need.

Trade-offs:

- Low-friction help.
- Weak fit for required instructions.

```tsx
import {
  Icon,
  IconButton,
  Text,
  Tooltip,
  TooltipArrow,
  TooltipContent,
  TooltipTrigger,
} from '@vega-ui/react';
import { ArchiveIcon, ReplyIcon, Trash2Icon } from '@vega-ui/icons';

const actions = [
  { label: 'Reply', hint: 'Reply to Maria Chen', icon: <ReplyIcon /> },
  { label: 'Archive', hint: 'Move to Archive · E', icon: <ArchiveIcon /> },
  { label: 'Delete', hint: 'Move to Trash · #', icon: <Trash2Icon /> },
];

export default function IconHint() {
  return (
    <div style={{ display: 'flex', gap: 'var(--spacing-2)' }}>
      {actions.map((action) => (
        <Tooltip key={action.label}>
          <TooltipTrigger asChild>
            <IconButton aria-label={action.label} variant='secondary' appearance='ghost'>
              <Icon>{action.icon}</Icon>
            </IconButton>
          </TooltipTrigger>
          <TooltipContent>
            <TooltipArrow />
            <Text size={2}>{action.hint}</Text>
          </TooltipContent>
        </Tooltip>
      ))}
    </div>
  );
}
```

### Field Helper

When to use:

- A field needs optional background context.

Composition notes:

- Keep the main label outside the tooltip.
- Use the tooltip only for optional explanation, not validation.

Trade-offs:

- Preserves clean forms.
- Easy to misuse for mandatory instructions.

```tsx
import { useId, useState, type FormEvent } from 'react';
import {
  Button,
  Icon,
  IconButton,
  Label,
  Text,
  TextField,
  TextFieldInput,
  Tooltip,
  TooltipArrow,
  TooltipContent,
  TooltipTrigger,
} from '@vega-ui/react';
import { InfoIcon } from '@vega-ui/icons';

export default function FieldHelper() {
  const fieldId = useId();
  const [saved, setSaved] = useState('');

  const onSubmit = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    setSaved(String(new FormData(event.currentTarget).get('vat')));
  };

  return (
    <form onSubmit={onSubmit} style={{ display: 'grid', gap: 'var(--spacing-3)', width: '100%' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-2)' }}>
        <Label htmlFor={fieldId}>VAT number (optional)</Label>
        <Tooltip>
          <TooltipTrigger asChild>
            <IconButton aria-label='About the VAT number' size='xs' variant='secondary' appearance='ghost'>
              <Icon size='xs'><InfoIcon /></Icon>
            </IconButton>
          </TooltipTrigger>
          <TooltipContent>
            <TooltipArrow />
            <Text size={2}>Printed on invoices for EU business customers</Text>
          </TooltipContent>
        </Tooltip>
      </div>
      <TextField>
        <TextFieldInput id={fieldId} name='vat' placeholder='DE123456789' pattern='[A-Z]{2}[A-Z0-9]{8,12}' />
      </TextField>
      <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-6)', marginBlockStart: 'var(--spacing-9)' }}>
        <Button type='submit' style={{ flexShrink: 0 }}>Save billing details</Button>
        <Text size={2} role='status' style={{ minWidth: 0, color: 'var(--label-secondary)', overflowWrap: 'anywhere' }}>{saved ? `Saved ${saved}` : ''}</Text>
      </div>
    </form>
  );
}
```

### Dense Data Hint

When to use:

- Tables, metrics, or compact settings rows need a very short explanation.

Composition notes:

- Keep the copy descriptive and scannable.
- Prefer one sentence over multi-step instructions.

Trade-offs:

- Helps preserve dense layouts.
- Breaks down quickly if the explanation becomes workflow guidance.

```tsx
import {
  Icon,
  IconButton,
  Text,
  Tooltip,
  TooltipArrow,
  TooltipContent,
  TooltipTrigger,
} from '@vega-ui/react';
import { InfoIcon } from '@vega-ui/icons';

const metrics = [
  { label: 'MRR', value: '$48,210', hint: 'Monthly recurring revenue from active subscriptions, excluding one-off charges' },
  { label: 'Churn', value: '2.4%', hint: 'Share of customers who cancelled in the last 30 days' },
  { label: 'Conversion', value: '6.8%', hint: 'Trials that became paid plans. Updated every 15 minutes' },
];

export default function DenseDataHint() {
  return (
    <dl
      style={{
        display: 'grid',
        gridTemplateColumns: 'repeat(3, minmax(0, 1fr))',
        gap: 'var(--spacing-8)',
        boxSizing: 'border-box',
        width: '100%',
        margin: 0,
        padding: 'var(--spacing-8)',
        background: 'var(--surface-primary)',
        border: '1px solid var(--separator-opaque)',
        borderRadius: 'var(--radius-5)',
      }}
    >
      {metrics.map((metric) => (
        <div key={metric.label} style={{ display: 'grid', gap: 'var(--spacing-1)', minWidth: 0 }}>
          <dt style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-1)' }}>
            <Text size={2} style={{ color: 'var(--label-secondary)' }}>{metric.label}</Text>
            <Tooltip>
              <TooltipTrigger asChild>
                <IconButton aria-label={`About ${metric.label}`} size='xs' variant='secondary' appearance='ghost'>
                  <Icon size='xs'><InfoIcon /></Icon>
                </IconButton>
              </TooltipTrigger>
              <TooltipContent>
                <TooltipArrow />
                <Text size={2} style={{ display: 'block', maxWidth: 240 }}>{metric.hint}</Text>
              </TooltipContent>
            </Tooltip>
          </dt>
          <dd style={{ margin: 0 }}><Text size={6} fontWeight={600} style={{ fontVariantNumeric: 'tabular-nums' }}>{metric.value}</Text></dd>
        </div>
      ))}
    </dl>
  );
}
```

## Comparison

### Quick Decision Rule

Choose `Tooltip` when the content is brief, supplemental, and non-essential.

### `Tooltip` vs `Popover`

Use `Tooltip` when:

- the content is just a hint or description

Use `Popover` when:

- the content is richer or interactive

### `Tooltip` vs `Dialog`

Use `Tooltip` when:

- the user does not need a modal interaction

Use `Dialog` when:

- the content represents an actual task flow

### Choose This Component When

- the content is a short hint
- the UI should stay non-modal and lightweight

### Do Not Choose This Component When

- the content is required, interactive, or task-oriented

## Troubleshooting

### Tooltip Content Feels Too Important

#### Symptom

Users need the tooltip to complete the task correctly.

#### Likely Cause

Required instructions were placed in a supplemental component.

#### How To Verify

- Hide the tooltip and check whether the control is still understandable.

#### Fix

- Move essential instructions into visible UI.

### Tooltip Inside Overlay Feels Unstable

#### Symptom

Tooltip timing or placement behaves oddly inside a dialog or other overlay.

#### Likely Cause

The tooltip was only tested in isolation.

#### How To Verify

- Render it inside the real overlay flow.

#### Fix

- Retest the exact stack and simplify where necessary.

### Tooltip Should Probably Be A Popover

#### Symptom

The content keeps growing and starts to need actions, form controls, or multiple paragraphs.

#### Likely Cause

Tooltip is being used for a richer contextual overlay than it was designed for.

#### How To Verify

- Check whether the content includes controls or task instructions.
- Compare the experience with `Popover`.

#### Fix

- Switch to `Popover` for richer contextual content.
- Keep tooltip content short and purely supplemental.
