Skip to main contentSkip to docs navigation

Dismissible notification component with automatic timeout, an addToast() queue via Toaster, and shorthand header/body/footer props.

A toast is a sm notification surface, modeled on the push notifications native to mobile and desktop operating systems. It's positioned and stacked with flexbox, so alignment follows the same margin and flexbox utility classes as the rest of Chassis.

Overview

<Toast> renders a single notification. Nothing shows until you ask for it.

  • Toasts are opt-in — nothing renders until visible or defaultVisible is set, or addToast() pushes one into a Toaster's queue.
  • defaultVisible shows a toast that then hides itself: by its close button, autohide, or close. visible makes it controlled: those become requests, reported to onVisibleChange(false), and the toast hides when you set visible to false. A state setter fits as it is: visible={open} onVisibleChange={setOpen}. onClose fires after the toast has hidden.
  • A toast automatically hides after delay milliseconds unless autohide is set to false. The countdown pauses while the pointer is over the toast or focus is within it, and only resumes once both leave.
  • Use role="status" (the default) for routine confirmations and informational updates. Reserve role="alert" for errors and messages requiring immediate attention. Both roles carry implicit live-region semantics, so no separate aria-live prop is needed.
  • The icon/title/time/message/footer/closeButton props are shorthand for the manual ToastHeader/ToastBody/ToastFooter composition — reach for manual composition only when a toast needs more than one header/body/footer block. See Shorthand props.
  • To dismiss a toast from custom markup — a "Close" button in the footer, a custom icon in the header — either pass a function to footer to receive close directly (see Action footer), or call useToast() from any child component and wire its close to an element's onClick.

Examples

Basic layout

A toast typically pairs a header and body — the header uses display: flex, aligning icon, title, and timestamp content with the margin and flexbox utility classes.

A toast needs very little required markup: at minimum, a single element containing its content. A dismiss button is recommended but not enforced.

Chassis7 min ago
Hello, world! This is a toast message.
JSX
import { Toast, ToastBody, ToastHeader, Icon } from '@chassis-ui/react'

export const Example = () => {
  const icon = <Icon name="info-circle-solid" />
  return (
    <Toast defaultVisible autohide={false}>
      <ToastHeader icon={icon} time="7 min ago" closeButton>
        Chassis
      </ToastHeader>
      <ToastBody>Hello, world! This is a toast message.</ToastBody>
    </Toast>
  )
}

For dynamic notifications, call addToast() from anywhere — an event handler, an async callback — to push a toast into a Toaster's queue. Toaster renders whatever's currently queued; nothing else needs to know about it.

JSX
import { Button, ToastBody, ToastHeader, Toaster, addToast, Icon } from '@chassis-ui/react'

export const Example = () => {
  const icon = <Icon name="info-circle-solid" />
  const handleClick = () => {
    addToast(
      <>
        <ToastHeader icon={icon} time="7 min ago" closeButton>
          Chassis
        </ToastHeader>
        <ToastBody>Hello, world! This is a toast message.</ToastBody>
      </>
    )
  }
  return (
    <>
      <Button onClick={handleClick}>Send a toast</Button>
      <Toaster placement="bottom-end" />
    </>
  )
}

Shorthand props

For the common case — an icon, a heading, a timestamp, one block of message text — icon/title/time/message render the same markup as composing ToastHeader/ToastBody by hand, without the wiring. icon accepts an icon name (rendered via ToastIcon) or any other node for a fully custom icon, such as a logo or avatar. Add footer for a single row of trailing content (shorthand for ToastFooter), and closeButton/closeLabel for the dismiss control and its accessible name. closeButton follows whatever header content is set: it lands in the header when icon/title/time is present, otherwise alongside message in the body — so a title-less toast never gets a header that exists only to hold a close button. When both title and message are set, the toast's aria-labelledby/aria-describedby are wired to them automatically. icon is hidden from assistive technology by default, since it duplicates title visually.

Chassis7 min ago
Hello, world! This is a toast message.
JSX
import { Toast, Icon } from '@chassis-ui/react'

export const Example = () => {
  const icon = <Icon name="info-circle-solid" />
  return (
    <Toast
      animation={false}
      autohide={false}
      defaultVisible
      icon={icon}
      title="Chassis"
      time="7 min ago"
      message="Hello, world! This is a toast message."
      closeButton
    />
  )
}

icon/title/time/message/footer are additive with children — for multi-block content (more than one header, body, or footer region), compose ToastHeader/ToastBody/ToastFooter manually instead, as in the sections below. ToastHeader itself takes the same shorthand shape — icon/time as props, the heading as children — so manual composition never requires hand-writing the <strong>/<span> markup.

Add a ToastFooter below the body to hold acknowledgement or follow-up actions, or pass footer for the same result without composing ToastFooter by hand — it renders .toast-footer, separated from the body by a border that matches the header rule.

A "Close" action is just a normal Button. Passing a function to footer provides close as its argument, so a button can wire it straight to onClick without a child component calling useToast() itself — useful when the footer's only custom need is the close handler. For anything with its own local state or logic, calling useToast() from a child component works the same way, and is the only option outside footer (a custom icon in the header, for example).

Hello, world! This is a toast message.
JSX
import { Button, Toast, ToastBody } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Toast
      autohide={false}
      defaultVisible
      footer={(close) => (
        <>
          <Button type="button" color="primary" size="sm">
            Take action
          </Button>
          <Button type="button" size="sm" onClick={close}>
            Close
          </Button>
        </>
      )}
    >
      <ToastBody>Hello, world! This is a toast message.</ToastBody>
    </Toast>
  )
}

Translucent

Add translucent to blend the toast in with what's below it.

Chassis7 min ago
Hello, world! This is a toast message.
JSX
import { Toast, ToastBody, ToastHeader, Icon } from '@chassis-ui/react'

export const Example = () => {
  const icon = <Icon name="info-circle-solid" />
  return (
    <Toast translucent autohide={false} defaultVisible>
      <ToastHeader icon={icon} time="7 min ago" closeButton>
        Chassis
      </ToastHeader>
      <ToastBody>Hello, world! This is a toast message.</ToastBody>
    </Toast>
  )
}

Stacking

Wrapping toasts in a Toaster stacks them, adding vertical spacing between each automatically.

Chassis7 min ago
Hello, world! This is a toast message.
Chassis7 min ago
Hello, world! This is a toast message.
JSX
import { Toast, ToastBody, ToastHeader, Toaster, Icon } from '@chassis-ui/react'

export const Example = () => {
  const icon = <Icon name="info-circle-solid" />
  return (
    <Toaster>
      <Toast autohide={false} defaultVisible>
        <ToastHeader icon={icon} time="7 min ago" closeButton>
          Chassis
        </ToastHeader>
        <ToastBody>Hello, world! This is a toast message.</ToastBody>
      </Toast>
      <Toast autohide={false} defaultVisible>
        <ToastHeader icon={icon} time="7 min ago" closeButton>
          Chassis
        </ToastHeader>
        <ToastBody>Hello, world! This is a toast message.</ToastBody>
      </Toast>
    </Toaster>
  )
}

Simplified layout

Toast sub-components can be omitted or adjusted with props to simplify the layout. This example removes the default <ToastHeader> and adds closeButton directly to <ToastBody>, so no manual markup is needed to lay out the dismiss control.

Hello, world! This is a toast message.
JSX
import { Toast } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Toast autohide={false} defaultVisible>
      Hello, world! This is a toast message.
    </Toast>
  )
}

Color schemes

Apply color and add solid for a full-color background with inverted text — the example below sets color="primary" and solid on the <Toast>.

Hello, world! This is a toast message.
JSX
import { Toast, ToastBody } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Toast autohide={false} defaultVisible color="primary" solid>
      <ToastBody closeButton>Hello, world! This is a toast message.</ToastBody>
    </Toast>
  )
}

API

Toast

PropTypeDefault
animation?booleantrue
Apply a CSS fade transition to the toast.
autohide?booleantrue
Auto hide the toast. The timer starts once the show transition completes and pauses while the pointer is over the toast or focus is within it.
className?string—
A string of all className you want applied to the base component.
closeButton?boolean—
Adds a close button — shorthand for ToastHeader's/ToastBody's closeButton prop. Placed in the header when icon/title/time is set; otherwise placed in the body alongside message, or in a header containing only the close button if message is also unset.
closeLabel?string—
Overrides the close button's accessible name (defaults to 'Close'). Set this for non-English UIs. Shorthand for ToastHeader's closeLabel prop.
color?ContextColor—
Sets the color of the component to one of Chassis context colors.
defaultVisible?booleanfalse
Whether the toast is shown when it first renders. Such a toast is uncontrolled: its close button and the autohide timer hide it. Use visible to show and hide it from outside.
delay?number5000
Delay hiding the toast (ms).
footer?ReactNode | ((close: () => void) => ReactNode)—
Trailing content — typically a row of Buttons — rendered via a single ToastFooter, after message/children. Pass a function to receive close directly, instead of calling useToast() from a child component to wire up a "Close" action.
icon?ReactNode—
Leading icon for the header. A string is an icon name, rendered like <ToastIcon name={icon} /> (or by IconProvider's component); pass any other node for a fully custom icon (typically a logo or avatar). Shorthand for ToastHeader's icon prop; hidden from assistive technology by default, since it duplicates title visually.
message?ReactNode—
Message body, rendered via a single ToastBody. For multi-block content, compose children manually instead — message wraps everything in one element.
onClose?(() => void)—
Callback fired once the toast has hidden: after its exit transition.
onShow?(() => void)—
Callback fired when the toast starts to show.
onVisibleChange?((visible: boolean) => void)—
Callback fired with false when the toast asks to hide: its close button, close from useToast or footer, or the autohide timer. With visible set, the toast hides only when visible becomes false.
role?"status" | "alert"status
ARIA live-region role. Use status (the default) for confirmation, progress, and informational messages, which announce politely. Use alert for messages that need immediate attention — validation errors, failed operations — which interrupt speech.
solid?boolean—
Apply a full-color background with inverted text. Only meaningful alongside color.
time?ReactNode—
Header timestamp, rendered after title. Shorthand for ToastHeader's time prop.
title?ReactNode—
Header heading, rendered before time. Shorthand for ToastHeader's children. When set alongside message, wires the toast's aria-labelledby/aria-describedby to them automatically.
translucent?boolean—
Apply a semi-transparent background.
visible?boolean—
Whether the toast is shown. Setting it makes the toast controlled: it hides only when this becomes false, so pair it with onVisibleChange. Without either visible or defaultVisible a toast renders nothing.

ToastHeader

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
children?ReactNode—
Heading, rendered before time as a <strong>.
className?string—
A string of all className you want applied to the base component.
closeButton?boolean—
Automatically add a close button to the header.
closeLabel?string—
Overrides the close button's accessible name (defaults to 'Close'). Set this for non-English UIs.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
icon?ReactNode—
Leading icon. A string is an icon name, rendered like <ToastIcon name={icon} /> (or by IconProvider's component) and hidden from assistive technology by default, since it duplicates the heading visually. Pass any other node for a fully custom icon (typically a logo or avatar) — a custom node is left as-is, since it may carry its own meaningful accessible name (e.g. an avatar's alt text).
ref?any—
time?ReactNode—
Trailing timestamp, rendered after the heading.
titleId?string—
Sets the id on the rendered heading element, for aria-labelledby wiring. Set automatically by Toast when both title and message are used together; only needed here for manual wiring in a fully custom composition.

ToastIcon

PropTypeDefault
className?string—
A string of all className you want applied to the component. A string of all className you want applied to the base component.
font?boolean—
namestring—
Icon name, e.g. folder-tree. Matches an id in the SVG sprite, or a cx-{name} font glyph class in font mode (see IconProvider's fontPrefix).
size?string | number—
Icon size: a number of pixels, or any CSS length ('1.25rem', '1em'). Sets chassis-css's --cx-icon-size on the icon, so it applies in font mode too. Leave unset to keep the size chassis-css gives icons in context (inside a button, an input, a navbar toggler, ...).
sprite?string—
URL of the SVG sprite file. Defaults to IconProvider's sprite, or to none — a sprite embedded in the page, referenced as #name. Ignored in font mode.
title?string—
Accessible name. When set, the icon is exposed to assistive tech instead of hidden.

ToastBody

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the base component.
closeButton?boolean—
Adds a close button alongside the body content, so a toast composed without a ToastHeader still gets a dismiss control without any manual layout markup.
closeLabel?string—
Overrides the close button's accessible name (defaults to 'Close'). Set this for non-English UIs.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
ref?any—

ToastFooter

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the base component.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
ref?any—

Toaster

PropTypeDefault
aria-label?string—
Overrides the toast region's accessible name (defaults to 'Notifications', per react-aria). Set this for non-English UIs, or to distinguish multiple toasters on the same page.
className?string—
A string of all className you want applied to the base component.
placement?'top-start' | 'top-center' | 'top-end' | 'middle-start' | 'middle-center' | 'middle-end' | 'bottom-start' | 'bottom-center' | 'bottom-end' | string—
Describes the placement of your component.