Toast
Transient status message with tone, position, and auto-dismiss.
Status: stable. Group: feedback. Markdown version: /design-system/components/toast.md
When to use
Toast is the transient "confirmation after action" surface: it appears, announces itself, and auto-dismisses. Most consumers never mount <Toast /> directly; the app-root ToastProvider (@/providers/ToastProvider) owns the single live region and exposes the imperative API: useToast() returns { showToast }, where showToast(message: string, options?: number | { tone?: ToastTone; duration?: number; position?: ToastPosition }) accepts a bare duration in ms (legacy) or an options object (duration defaults to 3000). The element stays mounted as a live region and swaps the message in/out, so assistive tech reliably announces every toast; errors and warnings escalate to role=alert automatically.
When not to use
- Do not mount two overlapping fixed <Toast /> instances yourself; use ToastStack (or the app ToastProvider) so concurrent messages stack instead of replacing each other.
- Do not rely on Toast for compliance acknowledgements (cookie consent, legal notices); it auto-dismisses; use AlertBanner or Modal.
- Do not use Toast for validation errors on a field; the message detaches from the input; use the field's error prop.
- Do not use Toast for persistent status, compliance acknowledgements, or anything the user must read; it disappears on its own. AlertBanner owns those.
Look-alikes
- AlertBanner: Do not use Toast for persistent status, compliance acknowledgements, or anything the user must read; it disappears on its own. AlertBanner owns those.
- Modal: Do not rely on Toast for compliance acknowledgements (cookie consent, legal notices); it auto-dismisses; use AlertBanner or Modal.
- ToastStack: Do not mount two overlapping fixed <Toast /> instances yourself; use ToastStack (or the app ToastProvider) so concurrent messages stack instead of replacing each other.
Props
| Prop | Type | Default | Description | Required |
|---|---|---|---|---|
open | boolean | none | Controls visibility. | No |
tone | "info" | "success" | "warning" | "error" | "neutral" | neutral | Semantic colour. | No |
position | "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right" | bottom-center | Position on screen. | No |
size | "sm" | "md" | "lg" | md | Size. | No |
message | string | none | Message text displayed in the toast. | Yes |
duration | number | 3000 | Auto-dismiss delay in ms. | No |
onClose | () => void | none | Called when the auto-dismiss timer fires. | No |
onDismiss | () => void | none | Renders a dismiss button that calls this, so a toast can be closed by hand and keyboard users can reach it (focus inside a ToastStack pauses its timers). The button sits outside the live region. | No |
dismissLabel | string | none | Accessible name of the dismiss button. Defaults to the translated "Dismiss notification" (toast.dismiss). | No |
inline | boolean | none | Render in normal document flow instead of fixed-positioning itself; a parent (ToastStack) owns placement. position is ignored when set. | No |
Variants
- Available sizes:
sm,md,lg(defaultmd). Forwarded to CSS module size classes. - Available tones:
neutral,success,error,warning,info(defaultneutral). - Available positions:
top-left,top-center,top-right,bottom-left,bottom-center,bottom-right(defaultbottom-center).
Invalid combinations
- SHOULD NOT: When
inlineistrue, then do not setposition. An inline toast is placed by its parent (ToastStack);positionis ignored.
Keyboard
The contract records no keyboard interaction.
Rules
Every item under When not to use is a MUST NOT. MUST and SHOULD follow RFC 2119.
| Level | Rule | How it is checked |
|---|---|---|
| SHOULD NOT | When inline is true, then do not set position. An inline toast is placed by its parent (ToastStack); position is ignored. | Checked by the MCP tool validate_component_usage (rule toast-inline-ignores-position). Also enforced in code: Toast.tsx: inline selects toast--inline instead of the position class. |
| MUST | ARIA: Role=status + aria-live=polite for neutral/info/success. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | ARIA: Role=alert + aria-live=assertive for warning/error. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | ARIA: Aria-atomic=true so the full message is announced. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | ARIA: Stays mounted as a live region; message swaps in/out. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | Required stories produce no axe violations at the configured severity. | Automated by npm run test:stories:matrix:ci. WCAG 2.5.8. |
| MUST | The accessibility tree (role, name, state) matches the committed snapshot for every required story. | Automated by npm run test:stories:matrix:ci. WCAG 1.3.1, 4.1.2. |
| MUST | The component remains legible and operable under a real browser forced-colors: active pass. | Automated by npm run test:stories:hc. |
| MUST | A human completed an end-to-end accessibility review of this component. | Manual review, last on 2026-11-04. |
| SHOULD | Fire toasts via useToast().showToast; the provider is mounted once at the app shell and handles the live region, position, and dismissal. | Not stated in the contract. |
| SHOULD | Keep the message to one short sentence; the toast auto-dismisses and cannot be paused, so long copy will be cut off mid-read. | Not stated in the contract. |
| SHOULD | Pass tone so the filled icon carries the meaning alongside color (WCAG 1.4.1); error and warning announce assertively on their own. | Not stated in the contract. |
| SHOULD | Raise duration (e.g. 5000-6000ms) for messages the user may need to act on, like a network-retry notice. | Not stated in the contract. |
| SHOULD NOT | Do not mount two <Toast /> instances side by side; the auto-dismiss timer is per instance but the announcement doubles in the AT queue. | Not stated in the contract. |
| SHOULD NOT | Do not put field validation errors in a toast; the message detaches from the field it describes; use the input's error prop. | Not stated in the contract. |
Install and import
- Install:
npm install @digitaltableteur/react(version 0.9.1, restricted access on npm). - Import:
import { Toast } from "@digitaltableteur/react"; - Entry point:
@digitaltableteur/react/feedbackexports it too. - Styles: import
@digitaltableteur/react/style.cssonce at the app boundary. - Also available as the custom element
<dt-toast>; see the custom elements manifest.
Links
- Machine-readable contract (Design System Contract 1.0)
- Markdown version of this page
- Component index as JSON
- All components
- Source: The implementation lives in a private repository. This page, its Markdown twin and the contract are generated from it at build time and are the public source of truth.