# Toast

A short message that shows above the page after an action.

```tsx
import { Button, toast } from 'ferry-ui'

export default function ToastHero() {
  return (
    <Button variant="primary" onClick={() => toast.success('Settings saved')}>
      Save changes
    </Button>
  )
}
```

## Usage guidelines

- **Feedback that does not stop the user.** A toast tells that something happened. Keep its title to one short sentence.
- **Not for a decision.** For an error that needs a decision, use [Confirm Dialog](/docs/components/confirm-dialog).
- **Not for a status that stays.** For a message that stays on the page, use [Callout](/docs/components/callout).
- **Import `toast` from `ferry-ui`.** Do not import it from `sonner`. The function and the `Toaster` then use the same copy of sonner.

## Anatomy

Mount `Toaster` one time, near the root of the app. Do not mount a second `Toaster`. Then call `toast()` in your event handlers.

```tsx title="app.tsx"

  return (
    <>
      <Button onClick={() => toast('Project archived')}>Archive</Button>
      <Toaster />
    </>
  )
}
```

<Callout tone="info" title="The copy components need the Toaster">
  [Copy](/docs/components/copy), [Code Block](/docs/components/code-block) and [useCopy](/docs/utilities/use-copy) show a toast when the copy fails.
</Callout>

## Examples

### Types

`toast()` shows a neutral message. The four other functions add a status icon.

```tsx
import { Button, toast } from 'ferry-ui'

export default function ToastTypes() {
  return (
    <>
      <Button onClick={() => toast('Project archived')}>Neutral</Button>
      <Button onClick={() => toast.success('Invoice sent')}>Success</Button>
      <Button onClick={() => toast.error('Payment failed')}>Error</Button>
      <Button onClick={() => toast.warning('Your trial ends in 3 days')}>Warning</Button>
      <Button onClick={() => toast.info('A new version is available')}>Info</Button>
    </>
  )
}
```

| Function | Use |
| --- | --- |
| `toast()` | A neutral message. |
| `toast.success()` | An action that is complete. |
| `toast.error()` | An action that failed. |
| `toast.warning()` | A problem that needs attention. |
| `toast.info()` | Information for the user. |

### Description

The second argument holds the options. Use `description` to add a second line.

```tsx
import { Button, toast } from 'ferry-ui'

export default function ToastDescription() {
  return (
    <Button
      onClick={() =>
        toast.success('Invoice sent', {
          description: 'The customer gets INV-2041 at billing@example.com.',
        })
      }
    >
      Send invoice
    </Button>
  )
}
```

### Action buttons

Use `action` to add a button to the toast. A click on this button runs `onClick` and closes the toast. Use `cancel` to add a second button.

```tsx
import { Button, toast } from 'ferry-ui'

export default function ToastAction() {
  return (
    <Button
      onClick={() =>
        toast('Project archived', {
          description: 'The project "Website redesign" is in the archive.',
          action: { label: 'Undo', onClick: () => toast.success('Project restored') },
          cancel: { label: 'Close', onClick: () => {} },
        })
      }
    >
      Archive project
    </Button>
  )
}
```

### Loading state

`toast.loading()` shows a spinner and returns the id of the toast. Pass this `id` to a second call to replace the toast.

```tsx
import { Button, toast } from 'ferry-ui'

export default function ToastLoading() {
  function exportMembers() {
    const id = toast.loading('Exporting the members…')
    // The same id replaces the toast in place.
    window.setTimeout(() => toast.success('Export ready', { id, description: '128 rows are in the file.' }), 2000)
  }

  return <Button onClick={exportMembers}>Export members</Button>
}
```

### Promise

`toast.promise()` follows a promise. It shows the `loading` message first, then the `success` message or the `error` message.

```tsx
import { Button, getErrorMessage, toast } from 'ferry-ui'

// A request that takes 1.5 seconds. Replace it with your own request.
function saveReport() {
  return new Promise<{ name: string }>((resolve) => {
    window.setTimeout(() => resolve({ name: 'Q3 report' }), 1500)
  })
}

export default function ToastPromise() {
  return (
    <Button
      onClick={() => {
        toast.promise(saveReport(), {
          loading: 'Saving the report…',
          success: (report) => `${report.name} saved`,
          error: (error: unknown) => getErrorMessage(error),
        })
      }}
    >
      Save report
    </Button>
  )
}
```

### Dismiss

`toast.dismiss(id)` closes one toast. With no argument, it closes all the toasts.

```tsx
import { Button, toast } from 'ferry-ui'

export default function ToastDismiss() {
  return (
    <>
      <Button onClick={() => toast.info('The import is in progress', { id: 'import', duration: Infinity })}>
        Show a toast that stays
      </Button>
      <Button variant="ghost" onClick={() => toast.dismiss('import')}>
        Dismiss it
      </Button>
      <Button variant="ghost" onClick={() => toast.dismiss()}>
        Dismiss all
      </Button>
    </>
  )
}
```

### Toaster options

`Toaster` shows the toasts at the bottom right, with a close button. It follows the theme of the app. Pass an option of sonner to change a default.

```tsx
<Toaster position="top-center" duration={8000} visibleToasts={5} />
```

## API reference

### Toaster

`Toaster` accepts each option of the sonner `Toaster`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `id` | `string` |  |  |
| `invert` | `boolean` |  |  |
| `theme` | `"light" \| "dark" \| "system"` |  |  |
| `position` | `"top-left" \| "top-right" \| "bottom-left" \| "bottom-right" \| "top-center" \| "bottom-center"` |  |  |
| `hotkey` | `string[]` |  |  |
| `richColors` | `boolean` |  |  |
| `expand` | `boolean` |  |  |
| `duration` | `number` |  |  |
| `gap` | `number` |  |  |
| `visibleToasts` | `number` |  |  |
| `closeButton` | `boolean` |  |  |
| `toastOptions` | `ToastOptions` |  |  |
| `className` | `string` |  |  |
| `style` | `CSSProperties` |  |  |
| `offset` | `Offset` |  |  |
| `mobileOffset` | `Offset` |  |  |
| `dir` | `"auto" \| "ltr" \| "rtl"` |  |  |
| `swipeDirections` | `SwipeDirection[]` |  |  |
| `icons` | `ToastIcons` |  |  |
| `customAriaLabel` | `string` |  |  |
| `containerAriaLabel` | `string` |  |  |

### toast

Each function that shows a toast returns the id of the toast.

| Function | Role |
| --- | --- |
| `toast(title, options)` | Shows a neutral toast. |
| `toast.success(title, options)` | Shows a toast with a success icon. |
| `toast.error(title, options)` | Shows a toast with an error icon. |
| `toast.warning(title, options)` | Shows a toast with a warning icon. |
| `toast.info(title, options)` | Shows a toast with an info icon. |
| `toast.loading(title, options)` | Shows a toast with a spinner. |
| `toast.promise(promise, messages)` | Shows the `loading`, `success` and `error` messages of a promise. |
| `toast.dismiss(id)` | Closes one toast, or all the toasts when there is no `id`. |

The options of a toast:

| Option | Type | Role |
| --- | --- | --- |
| `description` | `ReactNode` | A second line below the title. |
| `action` | `{ label, onClick }` | A button that runs `onClick` and closes the toast. |
| `cancel` | `{ label, onClick }` | A second button. |
| `id` | `string` or `number` | The id of the toast. A call with the same id replaces the toast. |
| `duration` | `number` | The time on screen, in milliseconds. |
