{"slug":"toast","title":"Toast","description":"Using the toast machine in your project.","contentType":"component","framework":"react","content":"The toast component is used to give feedback to users after an action has taken\nplace.\n\n## Resources\n\n\n[Latest version: v1.31.0](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- Support for screen readers\n- Limit the number of visible toasts\n- Manage promises within toast\n- Pause on hover, focus or page idle\n- Can remove or update toast programmatically\n\n## Installation\n\nTo use the toast machine in your project, run the following command in your\ncommand line:\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\nTo set up the toast correctly, you'll need to understand its anatomy and how we\nname its parts.\n\n> Each part includes a `data-part` attribute to help identify them in the DOM.\n\n\n\n## Usage\n\nFirst, import the toast package into your project\n\n```jsx\nimport * as toast from \"@zag-js/toast\"\n```\n\nNext, import the required hooks and functions for your framework and use the\ntoast machine in your project 🔥\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\nThe use the toast effectively, you need to understand these key aspects:\n\n### Toast Group\n\n- `toast.group.machine` — The state machine representation of a group of toasts.\n  It is responsible for spawning, updating and removing toasts.\n- `toast.group.connect` — function gives you access to methods you can use to\n  add, update, and remove a toast.\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` — The state machine representation of a single toast.\n- `toast.connect` — The function that takes the toast machine and returns\n  methods and JSX properties.\n\n## Creating a toast\n\nThere are five toast types that can be created with the toast machine. `info`,\n`success`, `loading`, `custom` and `error`.\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  `loading`, or `custom`.\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\n## Changing the placement\n\nUse the `placement` property when you call the `toaster.create(...)` to change\nthe position of the toast.\n\n```jsx {4}\ntoaster.info({\n  title: \"Hello World\",\n  description: \"This is a toast\",\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\nWhen using overlap, the toast's placement must match the `placement` of the\ntoast group (which is `bottom` by default).\n\n> Be sure to set up the [required styles](#requirement) to make the toasts\n> overlap 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\n> You can also use the `toaster.upsert(...)` function which creates or updates a\n> toast.\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.upsert(...)` — Creates or updates a toast.\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\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  placement: \"top-start\",\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## 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## Pausing the toasts\n\nThere are three scenarios we provide to pause a toast from timing out:\n\n- When the document loses focus or the page is idle (e.g. switching to a new\n  browser tab), controlled via the `pauseOnPageIdle` context property.\n- When the `toaster.pause(id)` is called.\n\n```jsx\n// Global pause options\nconst service = useMachine(toast.group.machine, {\n  pauseOnPageIdle: true,\n})\n\n// Programmatically pause a toast (by `id`)\n// `id` is the return value of `api.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 the number of visible toasts, pass the `max` property to\nthe group machine's context.\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` context property to change the underlying hotkey.\n\n```jsx\nconst service = useMachine(toast.group.machine, {\n  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- `dismissed` - The toast is visually invisible 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\" | \"dismissed\" | \"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 the `gap` context property.\n\n```jsx {3}\nconst service = useMachine(toast.group.machine, {\n  gap: 24,\n})\n```\n\n## Changing the offset\n\nThe toast region has a default `16px` offset from the viewport. Use the `offset`\ncontext property to change the offset.\n\n```jsx {4-8}\nconst service = useMachine(toast.group.machine, {\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 it transition smoothly, you should includes `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"}