FSAI Design System
Components

Toast

Composable notification primitives and default toast chrome used by the platform toast system.

Overview

The shared toast UI is layered:

LayerRole
Toast primitivesLow-level layout and styling pieces
DefaultToastStandard composed toast used by platform helpers
showToast / showPromiseToastThe normal imperative API most product code should use

This page documents the component layer: the composable toast building blocks and the default toast component they produce.

In most product code, do not build toasts by hand. Use showToast instead. Only drop down to the component layer when you need a special toast layout or when you are extending the notification system itself.

See the toasts patterns page for the normal platform guidance.

Architecture

The toast stack is implemented in shared UI as:

  • primitives in @fsai/shared-ui/src/primitives/Toast/Toast.tsx
  • composed component exports in @fsai/shared-ui/src/components/Toast/Toast.tsx
  • imperative helpers in @fsai/shared-ui/src/components/Toast/Toast.utils.tsx

The visual default used across the brand dashboard is DefaultToast, not raw react-toastify output.

Basic Composition

import { Toast } from '@fsai/shared-ui';

<Toast type="success">
  <Toast.Body>
    <Toast.Icon type="success" />
    <div className="flex-1 min-w-0">
      <Toast.Title type="success">Saved</Toast.Title>
      <Toast.Description>Changes were saved successfully.</Toast.Description>
    </div>
  </Toast.Body>
</Toast>

This is the low-level compound API. It is useful when you need custom layout but still want the shared toast styling and semantics.

Default Toast

DefaultToast is the standard composed implementation used by showToast.

It handles:

  • type-based icon and styling
  • optional title
  • description/content area
  • optional action buttons
  • optional close button
import { DefaultToast } from '@fsai/shared-ui';

<DefaultToast
  type="neutral"
  title="Lead Deleted"
  content="The lead has been deleted"
  actions={[
    {
      text: 'Undo',
      onClick: handleUndo,
    },
  ]}
/>

Toast Portal

ToastPortal mounts the shared react-toastify container into #toast-root.

In application code, this is usually mounted once near the app root. In the brand dashboard:

  • index.html provides #toast-root
  • App.tsx mounts <ToastPortal />
  • App.tsx also imports react-toastify/dist/ReactToastify.css

If the portal or root node is missing, platform toasts will not render.

Compound API

ExportPurpose
ToastThin wrapper around the primitive container with static subcomponents attached
Toast.BodyMain horizontal layout row
Toast.IconType-based icon, with optional icon override
Toast.TitleTitle row with type-aware coloring
Toast.DescriptionSecondary text/content area
Toast.ActionsContainerAction button row
Toast.CloseClose affordance
DefaultToastStandard ready-to-render composed toast
ToastPortalShared toast container portal

Primitive Behavior

type

The shared toast types are:

  • success
  • neutral
  • info
  • error

These control:

  • background color
  • title color
  • default icon
  • accessibility semantics

Accessibility behavior comes from the primitive container:

  • error uses role="alert" and aria-live="assertive"
  • other types use role="status" and aria-live="polite"

Props

Toast

PropTypeDefaultDescription
type'success' | 'neutral' | 'info' | 'error'Required. Visual and semantic toast type.
childrenReactNodeRequired. Toast content tree.
classNamestringAdditional container classes.

DefaultToast

PropTypeDefaultDescription
type'success' | 'neutral' | 'info' | 'error'Required. Toast type.
contentReactNodeRequired. Main toast description/content.
titlestringOptional title above the content.
actions{ text, onClick, leftAdornment?, rightAdornment? }[]Optional action buttons.
onClose() => void | nullOptional close handler.
iconIconNameOptional icon override.

ToastPortal

ToastPortal does not take props. It renders a shared ToastContainer with platform defaults:

  • bottom-right placement
  • autoClose={10000}
  • hidden progress bar
  • no built-in toastify close button
  • closeOnClick={false}

When Custom Composition Fits

Reach for the component layer when:

  • you are extending the shared toast system itself
  • you need custom content but still want shared toast styling
  • you need a composed layout that showToast does not express cleanly
  • you are building a toast that will be rendered through react-toastify manually

For example, UploadProgressToast uses a fully custom layout and is updated over time with toast.update(...) rather than rendered through DefaultToast.

Brand Dashboard Usage

Representative usages:

PatternPathNotes
App-level containerfsai/apps/brand-dashboard/src/App.tsxMounts ToastPortal once for the app.
Undoable action toastfsai/apps/brand-dashboard/src/pages/Leads/Leads.tsxUses showToast, which renders DefaultToast with actions.
Promise lifecycle toastfsai/apps/brand-dashboard/src/pages/Analytics/components/AnalyticsReportsDialog/AnalyticsReportsDialog.tsxUses showPromiseToast, which still renders DefaultToast.
Fully custom progress toastfsai/apps/brand-dashboard/src/context/UploadContext/UploadContext.tsxUses raw react-toastify updates with UploadProgressToast.

Important Conventions

  • Prefer showToast and showPromiseToast over manual composition in product code.
  • DefaultToast is the shared default chrome for platform notifications.
  • ToastPortal must be mounted once at the app level for shared toasts to appear.
  • Toast component docs are about UI composition, not about when a workflow should trigger a toast.
  • The brand-dashboard modules/toast area is for Toast POS integration, not the UI notification component.

Guidelines

  • Do use Toast and DefaultToast when you need custom toast rendering infrastructure
  • Do rely on the shared types and semantics instead of inventing new toast color schemes
  • Do keep custom toast layouts compact and notification-sized
  • Don't compose raw toast chrome in ordinary feature code when showToast already fits
  • Don't confuse UI toasts with the unrelated Toast POS integration modules

On this page