{"slug":"toast","title":"Toast","description":"Using the toast machine in your project.","contentType":"component","framework":"react","content":"Toast provides brief feedback after an action.\n\n## Resources\n\n\n[Latest version: v1.35.3](https://www.npmjs.com/package/@zag-js/toast)\n[Logic Visualizer](https://zag-visualizer.vercel.app/toast)\n[Source Code](https://github.com/chakra-ui/zag/tree/main/packages/machines/toast)\n\n\n\n**Features**\n\n- Supports screen readers\n- Limits the number of visible toasts\n- Handles promise lifecycles\n- Pauses on hover, focus, or page idle\n- Supports programmatic update/remove\n\n## Installation\n\nInstall the toast package:\n\n```bash\nnpm install @zag-js/toast @zag-js/react\n# or\nyarn add @zag-js/toast @zag-js/react\n```\n\n## Anatomy\n\nCheck the toast anatomy and part names.\n\n> Each part includes a `data-part` attribute to help identify them in the DOM.\n\n\n\n## Usage\n\nImport the toast package:\n\n```jsx\nimport * as toast from \"@zag-js/toast\"\n```\n\nThen use the framework integration helpers:\n\n```jsx\nimport { useMachine, normalizeProps } from \"@zag-js/react\"\nimport * as toast from \"@zag-js/toast\"\nimport { useId } from \"react\"\n\n// 1. Create the toast store\nconst toaster = toast.createStore({\n  overlap: true,\n  placement: \"top-end\",\n})\n\n// 2. Design the toast component\nfunction Toast(props) {\n  const machineProps = {\n    ...props.toast,\n    parent: props.parent,\n    index: props.index,\n  }\n  const service = useMachine(toast.machine, machineProps)\n  const api = toast.connect(service, normalizeProps)\n\n  return (\n    <div {...api.getRootProps()}>\n      <h3 {...api.getTitleProps()}>{api.title}</h3>\n      <p {...api.getDescriptionProps()}>{api.description}</p>\n      <button onClick={api.dismiss}>Close</button>\n    </div>\n  )\n}\n\n// 3. Design the toaster\nexport function Toaster() {\n  const service = useMachine(toast.group.machine, {\n    id: useId(),\n    store: toaster,\n  })\n  const api = toast.group.connect(service, normalizeProps)\n  return (\n    <div {...api.getGroupProps()}>\n      {api.getToasts().map((toast, index) => (\n        <Toast key={toast.id} toast={toast} parent={service} index={index} />\n      ))}\n    </div>\n  )\n}\n\n// 4. Render the toaster in your app\nexport function App() {\n  return (\n    <>\n      <Toaster />\n      <ExampleComponent />\n    </>\n  )\n}\n\n// 5. Within your app\nfunction Demo() {\n  return (\n    <div>\n      <button\n        onClick={() => {\n          toaster.create({ title: \"Hello\" })\n        }}\n      >\n        Info toast\n      </button>\n      <button\n        onClick={() => {\n          toaster.create({ title: \"Data submitted!\", type: \"success\" })\n        }}\n      >\n        Success toast\n      </button>\n    </div>\n  )\n}\n```\n\nTo use toast effectively, understand these key parts:\n\n### Toast Group\n\n- `toast.group.machine` - State machine logic for the toast region.\n- `toast.group.connect` - Maps group state to JSX props and subscriptions.\n\n  > We recommend setting up the toast group machine once at the root of your\n  > project.\n\n### Toast Item\n\n- `toast.machine` - State machine logic for a single toast.\n- `toast.connect` - Maps toast state to JSX props and controls.\n\n## Creating a toast\n\nCommon toast types are `info`, `success`, `warning`, `loading`, and `error`. You\ncan also pass a custom type string.\n\nHelper methods are also available: `toaster.info(...)`, `toaster.success(...)`,\n`toaster.warning(...)`, `toaster.error(...)`, and `toaster.loading(...)`.\n\nTo create a toast, use the `toaster.create(...)` method.\n\n```jsx\ntoaster.create({\n  title: \"Hello World\",\n  description: \"This is a toast\",\n  type: \"info\",\n})\n```\n\nThe options you can pass in are:\n\n- `title` — The title of the toast.\n- `description` — The description of the toast.\n- `type` — The type of the toast. Can be either `error`, `success` , `info`,\n  `warning`, `loading`, or any custom string.\n- `duration` — The duration of the toast. The default duration is computed based\n  on the specified `type`.\n- `onStatusChange` — A callback that listens for the status changes across the\n  toast lifecycle.\n- `removeDelay` — The delay before unmounting the toast from the DOM. Useful for\n  transition.\n- `action` — Optional action button with `label` and `onClick`.\n- `closable` — Whether to render a close trigger.\n\n## Changing the placement\n\nPlacement is configured on the toast store and applies to the whole toast group.\n\n```jsx\nconst toaster = toast.createStore({\n  placement: \"top-start\",\n})\n```\n\n## Overlapping toasts\n\nWhen multiple toasts are created, they are rendered in a stack. To make the\ntoasts overlap, set the `overlap` property to `true`.\n\n```jsx\nconst toaster = toast.createStore({\n  overlap: true,\n})\n```\n\n> Be sure to set up the [required styles](#requirement) to make overlap work\n> correctly.\n\n## Changing the duration\n\nEvery toast has a default visible duration depending on the `type` set. Here's\nthe following toast types and matching default durations:\n\n<PropValueTable\n  items={{\n    headings: [\"type\", \"duration\"],\n    data: [\n      [\"info\", \"5000\"],\n      [\"error\", \"5000\"],\n      [\"success\", \"2000\"],\n      [\"loading\", \"Infinity\"],\n    ],\n  }}\n/>\n\nYou can override the duration of the toast by passing the `duration` property to\nthe `toaster.create(...)` function.\n\n```jsx {5}\ntoaster.create({\n  title: \"Hello World\",\n  description: \"This is a toast\",\n  type: \"info\",\n  duration: 6000,\n})\n```\n\nUse `toaster.create(...)` for new toasts and `toaster.update(id, ...)` to modify\nan existing one.\n\n## Using portals\n\nUsing a portal is helpful to ensure that the toast is rendered outside the DOM\nhierarchy of the parent component. To render the toast in a portal, wrap the\nrendered toasts in the `ToastProvider` within your framework-specific portal.\n\n```jsx {1,12,14}\nimport { useMachine, normalizeProps, Portal } from \"@zag-js/react\"\nimport * as toast from \"@zag-js/toast\"\n\n// ...\n\n// 3. Create the toast group provider, wrap your app with it\nexport function Toaster() {\n  const service = useMachine(toast.group.machine, { id: \"1\", store: toaster })\n  const api = toast.group.connect(service, normalizeProps)\n\n  return (\n    <Portal>\n      {api.getToasts().map((toast, index) => (\n        <Toast key={toast.id} actor={toast} parent={service} index={index} />\n      ))}\n    </Portal>\n  )\n}\n```\n\n## Programmatic control\n\nTo update a toast programmatically, you need access to the unique identifier of\nthe toast.\n\nThis identifier can be either:\n\n- the `id` passed into `toaster.create(...)` or,\n- the returned random `id` when the `toaster.create(...)` is called.\n\nYou can use any of the following methods to control a toast:\n\n- `toaster.update(...)` — Updates a toast.\n- `toaster.remove(...)` — Removes a toast instantly without delay.\n- `toaster.dismiss(...)` — Removes a toast with delay.\n- `toaster.pause(...)` — Pauses a toast.\n- `toaster.resume(...)` — Resumes a toast.\n- `toaster.isVisible(...)` — Checks if a toast is currently visible.\n- `toaster.isDismissed(...)` — Checks if a toast has been dismissed.\n\n```jsx {2,11-15}\n// grab the id from the created toast\nconst id = toaster.create({\n  title: \"Hello World\",\n  description: \"This is a toast\",\n  type: \"info\",\n  duration: 6000,\n})\n\n// update the toast\ntoaster.update(id, {\n  title: \"Hello World\",\n  description: \"This is a toast\",\n  type: \"success\",\n})\n\n// remove the toast\ntoaster.remove(id)\n\n// dismiss the toast\ntoaster.dismiss(id)\n```\n\n### Pause and resume all toasts\n\nCall `pause()`/`resume()` without an `id` to affect all active toasts.\n\n```jsx\ntoaster.pause()\ntoaster.resume()\n```\n\n## Handling promises\n\nThe toast group API exposes a `toaster.promise()` function to allow you update\nthe toast when it resolves or rejects.\n\n> With the promise API, you can pass the toast options for each promise\n> lifecycle. **The `loading` option is required**\n\n```jsx\ntoaster.promise(promise, {\n  loading: {\n    title: \"Loading\",\n    description: \"Please wait...\",\n  },\n  success: (data) => ({\n    title: \"Success\",\n    description: \"Your request has been completed\",\n  }),\n  error: (err) => ({\n    title: \"Error\",\n    description: \"An error has occurred\",\n  }),\n})\n```\n\n`toaster.promise(...)` returns `{ id, unwrap }`, so you can await the original\nresult:\n\n```jsx\nconst result = toaster.promise(fetchData(), {\n  loading: { title: \"Loading...\" },\n})\nawait result?.unwrap()\n```\n\n## Pausing the toasts\n\nThere are three scenarios that pause toast timeout:\n\n- When a user hovers or focuses the toast region.\n- When the document loses focus or the page is idle (e.g. switching to a new\n  browser tab), controlled via the `pauseOnPageIdle` store option.\n- When the `toaster.pause(id)` is called.\n\n```jsx\n// Global pause options\nconst toaster = toast.createStore({\n  pauseOnPageIdle: true,\n})\n\n// Programmatically pause a toast (by `id`)\n// `id` is the return value of `toaster.create(...)`\ntoaster.pause(id)\n```\n\n## Limiting the number of toasts\n\nToasts are great but displaying too many of them can sometimes hamper the user\nexperience. To limit visible toasts, set `max` on the store.\n\n```jsx {3}\nconst toaster = toast.createStore({\n  max: 10,\n})\n```\n\n## Focus Hotkey for toasts\n\nWhen a toast is created, you can focus the toast region by pressing the\n`alt + T`. This is useful for screen readers and keyboard navigation.\n\nSet the `hotkey` store option to change the underlying hotkey.\n\n```jsx\nconst service = useMachine(toast.group.machine, {\n  store: toast.createStore({ hotkey: [\"F6\"] }),\n})\n```\n\n## Listening for toast lifecycle\n\nWhen a toast is created, you can listen for the status changes across its\nlifecycle using the `onStatusChange` callback when you call\n`toaster.create(...)`.\n\nThe status values are:\n\n- `visible` - The toast is mounted and rendered\n- `dismissing` - The toast is closing but still mounted\n- `unmounted` - The toast has been completely unmounted and no longer exists\n\n```jsx {3-7}\ntoaster.info({\n  title: \"Hello World\",\n  description: \"This is a toast\",\n  type: \"info\",\n  onStatusChange: (details) => {\n    // details => { status: \"visible\" | \"dismissing\" | \"unmounted\" }\n    console.log(\"Toast status:\", details)\n  },\n})\n```\n\n## Changing the gap between toasts\n\nWhen multiple toasts are rendered, a gap of `16px` is applied between each\ntoast. To change this value, set `gap` on the store.\n\n```jsx\nconst toaster = toast.createStore({\n  gap: 24,\n})\n```\n\n## Changing the offset\n\nThe toast region has a default `1rem` offset from the viewport. Use the\n`offsets` store option to change this offset.\n\n```jsx\nconst toaster = toast.createStore({\n  offsets: \"24px\",\n})\n```\n\n## Styling guide\n\n### Requirement\n\nThe toast machine injects a bunch of css variables that are required for it to\nwork. You need to connect these variables in your styles.\n\n```css\n[data-part=\"root\"] {\n  translate: var(--x) var(--y);\n  scale: var(--scale);\n  z-index: var(--z-index);\n  height: var(--height);\n  opacity: var(--opacity);\n  will-change: translate, opacity, scale;\n}\n```\n\nTo make transitions smooth, include `transition` properties.\n\n```css\n[data-part=\"root\"] {\n  transition:\n    translate 400ms,\n    scale 400ms,\n    opacity 400ms;\n  transition-timing-function: cubic-bezier(0.21, 1.02, 0.73, 1);\n}\n\n[data-part=\"root\"][data-state=\"closed\"] {\n  transition:\n    translate 400ms,\n    scale 400ms,\n    opacity 200ms;\n  transition-timing-function: cubic-bezier(0.06, 0.71, 0.55, 1);\n}\n```\n\n### Toast styling\n\nWhen a toast is created and the `api.getRootProps()` from the `toast.connect` is\nused, the toast will have a `data-type` that matches the specified `type` at its\ncreation.\n\nYou can use this property to style the toast.\n\n```css\n[data-part=\"root\"][data-type=\"info\"] {\n  /* Styles for the specific toast type */\n}\n\n[data-part=\"root\"][data-type=\"error\"] {\n  /* Styles for the error toast type */\n}\n\n[data-part=\"root\"][data-type=\"success\"] {\n  /* Styles for the success toast type */\n}\n\n[data-part=\"root\"][data-type=\"loading\"] {\n  /* Styles for the loading toast type */\n}\n```\n\n## Methods and Properties\n\n### Machine API\n\nThe toast's `api` exposes the following methods:\n\n**`getCount`**\nType: `() => number`\nDescription: The total number of toasts\n\n**`getToasts`**\nType: `() => ToastProps<any>[]`\nDescription: The toasts\n\n**`subscribe`**\nType: `(callback: (toasts: Options<O>[]) => void) => VoidFunction`\nDescription: Subscribe to the toast group\n\n### Data Attributes\n\n**`Root`**\n\n**`data-scope`**: toast\n**`data-part`**: root\n**`data-state`**: \"open\" | \"closed\"\n**`data-type`**: The type of the item\n**`data-placement`**: The placement of the toast\n**`data-align`**: \n**`data-side`**: \n**`data-mounted`**: Present when mounted\n**`data-paused`**: Present when paused\n**`data-first`**: \n**`data-sibling`**: \n**`data-stack`**: \n**`data-overlap`**: Present when overlapping\n\n**`GhostBefore`**\n\n**`data-scope`**: toast\n**`data-part`**: ghost-before\n**`data-ghost`**: \n\n**`GhostAfter`**\n\n**`data-scope`**: toast\n**`data-part`**: ghost-after\n**`data-ghost`**: \n\n### CSS Variables\n\n<CssVarTable name=\"toast\" />","package":"@zag-js/toast","editUrl":"https://github.com/chakra-ui/zag/edit/main/website/data/components/toast.mdx"}