Default

Loading interactive example. Full source is available below.

View example source
Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import { ToastBody } from "@coreai-ds/react-components";
import { ToastFooter } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import * as React from 'react';

export const Default = (): JSXElement => {
    const toasterId = useId('toaster');
    const { dispatchToast } = useToastController(toasterId);
    const notify = () => dispatchToast(<Toast>
        <ToastTitle action={<Link>Undo</Link>}>Email sent</ToastTitle>
        <ToastBody subtitle="Subtitle">This is a toast body</ToastBody>
        <ToastFooter>
          <Link>Action</Link>
          <Link>Action</Link>
        </ToastFooter>
      </Toast>, { intent: 'success' });
    return (<>
      <Toaster toasterId={toasterId}/>
      <Button onClick={notify}>Make toast</Button>
    </>);
};

export default Default;

Resources

Best practices

Do

  • Use toasts for non-critical messages.
  • Configure defaults on the toaster.
  • Let people view toast content in the application after the toast is dismissed.
  • Create a keyboard shortcut to move focus to actionable toasts.

Don't

  • Render too many toasts at once.
  • Use different positions for toasts.
  • Use more than one toaster in an application.
  • Make every toast use assertive politeness.

Behavior and states

  • Use toasts to communicate task status, progress, required actions, application updates, or errors.
  • Make notifications available on a permanent surface so important information remains accessible.
API referenceGenerated CoreAI prop and type summaries

API

Generated CoreAI prop summaries, not replacement type declarations. Most native DOM/event and ARIA props are omitted. ? means optional; JSDoc shows defaults, deprecations, and conditional requirements. Defaults assume the standard CoreAI provider.

Toast API

Toast component

interface ToastProps {
  appearance?: "brand" | "inverted";

  as?: "div";

  children?: any;

  className?: string;

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;
}

ToastBody API

ToastBody component

interface ToastBodyProps {
  as?: "div";

  children?: any;

  className?: string;

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;

  subtitle?: WithSlotShorthandValue<{ as?: "div"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null; }, "children"> & { children?: any; }> | null | undefined;
}

ToastFooter API

ToastFooter component

interface ToastFooterProps {
  as?: "div";

  children?: any;

  className?: string;

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;
}

ToastTitle API

ToastTitle component

interface ToastTitleProps {
  action?: WithSlotShorthandValue<{ as?: "div"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null; }, "children"> & { children?: any; }> | null | undefined;

  as?: "div";

  children?: any;

  className?: string;

  media?: WithSlotShorthandValue<{ as?: "div"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null; }, "children"> & { children?: any; }> | null | undefined;

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;
}

Toaster API

Toaster component - renders a collection of toasts dispatched imperatively

interface ToasterProps {
  /**
   * User override API for aria-live narration for toasts
   */
  announce?: ToastAnnounce;

  as?: "div";

  className?: string;

  inline?: boolean;

  limit?: number;

  /**
   * Where the portal children are mounted on DOM
   * @default a new element on document.body without any styling
   */
  mountNode?: HTMLElement | { element?: HTMLElement | null; className?: string; } | null | undefined;

  offset?: ToastOffset;

  /**
   * Toast timeout pauses while user cursor is on the toast
   * @default false
   */
  pauseOnHover?: boolean;

  /**
   * Toast timeout pauses while focus is on another window
   * @default false
   */
  pauseOnWindowBlur?: boolean;

  /**
   * The position the toast should render to
   */
  position?: "top" | "bottom" | "top-end" | "top-start" | "bottom-end" | "bottom-start";

  /**
   * Higher priority toasts will be rendered before lower priority toasts
   */
  priority?: number;

  shortcuts?: ToasterShortcuts;

  style?: CSSProperties;

  /**
   * Auto dismiss timeout in milliseconds
   * @default 3000
   */
  timeout?: number;

  toasterId?: string;
}

Implementation

CoreAI 0.12.0; Fluent 9.74.9.

Setup and dependencies.

Import components from @coreai-ds/react-components. CoreAI guidance above takes precedence over API demonstration examples.

Custom Timeout

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { ToastTrigger } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { SpinButton } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";

export const CustomTimeout = (): JSXElement => {
    const [timeout, setDismissTimeout] = React.useState(1000);
    const toasterId = useId('toaster');
    const { dispatchToast } = useToastController(toasterId);
    const notify = () => dispatchToast(<Toast>
        <ToastTitle action={<ToastTrigger>
              <Link>Dismiss</Link>
            </ToastTrigger>}>
          {timeout >= 0 ? `Custom timeout ${timeout}ms` : `Dismiss manually`}
        </ToastTitle>
      </Toast>, { timeout, intent: 'info' });
    return (<>
      <Field label="Timeout" hint="Timeout is in milliseconds">
        <SpinButton value={timeout} onChange={(e, data) => {
            if (data.value) {
                setDismissTimeout(data.value);
            }
            else if (data.displayValue !== undefined) {
                const newValue = parseFloat(data.displayValue);
                if (!Number.isNaN(newValue)) {
                    setDismissTimeout(newValue);
                }
            }
        }}/>
      </Field>
      <br />
      <Toaster toasterId={toasterId}/>
      <Button onClick={notify}>Make toast</Button>
    </>);
};

export default CustomTimeout;

Default Toast Options

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import * as React from 'react';

export const DefaultToastOptions = (): JSXElement => {
    const toasterId = useId('toaster');
    const { dispatchToast } = useToastController(toasterId);
    const notify = () => dispatchToast(<Toast>
        <ToastTitle>Options configured in Toaster</ToastTitle>
      </Toast>, { intent: 'info' });
    return (<>
      <Toaster toasterId={toasterId} position="top-end" pauseOnHover pauseOnWindowBlur timeout={1000}/>
      <Button onClick={notify}>Make toast</Button>
    </>);
};

export default DefaultToastOptions;

Dismiss All

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import * as React from 'react';

export const DismissAll = (): JSXElement => {
    const toasterId = useId('toaster');
    const { dispatchToast, dismissAllToasts } = useToastController(toasterId);
    const notify = () => dispatchToast(<Toast>
        <ToastTitle>This is a toast</ToastTitle>
      </Toast>, { intent: 'info' });
    const dismissAll = () => dismissAllToasts();
    return (<>
      <Toaster toasterId={toasterId}/>
      <Button onClick={notify}>Make toast</Button>
      <Button onClick={dismissAll}>Dismiss all toasts</Button>
    </>);
};

export default DismissAll;

Dismiss Toast

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import * as React from 'react';
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";

export const DismissToast = (): JSXElement => {
    const toasterId = useId('toaster');
    const toastId = useId('example');
    const [unmounted, setUnmounted] = React.useState(true);
    const { dispatchToast, dismissToast } = useToastController(toasterId);
    const notify = () => {
        dispatchToast(<Toast>
        <ToastTitle>This is a toast</ToastTitle>
      </Toast>, { toastId, intent: 'success', onStatusChange: (e, { status }) => setUnmounted(status === 'unmounted') });
        setUnmounted(false);
    };
    const dismiss = () => dismissToast(toastId);
    return (<>
      <Toaster toasterId={toasterId}/>
      <Button onClick={unmounted ? notify : dismiss}>{unmounted ? 'Make' : 'Dismiss'} toast</Button>
    </>);
};

export default DismissToast;

Dismiss Toast With Action

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { ToastTrigger } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import * as React from 'react';

export const DismissToastWithAction = (): JSXElement => {
    const toasterId = useId('toaster');
    const { dispatchToast } = useToastController(toasterId);
    const notify = () => dispatchToast(<Toast>
        <ToastTitle action={<ToastTrigger>
              <Link>Dismiss</Link>
            </ToastTrigger>}>
          Dismiss me
        </ToastTitle>
      </Toast>, { intent: 'success' });
    return (<>
      <Toaster toasterId={toasterId}/>
      <Button onClick={notify}>Make toast</Button>
    </>);
};

export default DismissToastWithAction;

Focus Keyboard Shortcut

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { ToastTrigger } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import { ToastBody } from "@coreai-ds/react-components";
import { ToastFooter } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import * as React from 'react';

export const FocusKeyboardShortcut = (): JSXElement => {
    const toasterId = useId('toaster');
    const { dispatchToast } = useToastController(toasterId);
    const notify = () => dispatchToast(<Toast>
        <ToastTitle action={<ToastTrigger>
              <Link>Dismiss</Link>
            </ToastTrigger>}>
          Email sent
        </ToastTitle>
        <ToastBody subtitle="Subtitle">This is a toast body</ToastBody>
        <ToastFooter>
          <Link>Action</Link>
          <Link>Action</Link>
        </ToastFooter>
      </Toast>, { intent: 'success' });
    return (<>
      <Toaster limit={3} shortcuts={{ focus: e => e.ctrlKey && e.key === 'm' }} toasterId={toasterId}/>
      <Button onClick={notify}>Make toast</Button>
    </>);
};

export default FocusKeyboardShortcut;

Inline

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    container: {
        border: '2px dashed green',
        height: '500px',
        width: '500px',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        position: 'relative',
        marginTop: '20px',
    },
});

export const Inline = (): JSXElement => {
    const styles = useStyles();
    const toasterId = useId('toaster');
    const { dispatchToast } = useToastController(toasterId);
    const notify = () => dispatchToast(<Toast>
        <ToastTitle action={<Link>Undo</Link>}>Email sent</ToastTitle>
      </Toast>, { intent: 'success' });
    return (<>
      <Button onClick={notify}>Make toast</Button>
      <div className={styles.container}>
        <Text weight="bold">Toasts appear here</Text>

        <Toaster inline toasterId={toasterId} position="bottom"/>
      </div>
    </>);
};

export default Inline;

Intent

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import * as React from 'react';
import type { ToastIntent } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Spinner } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { RadioGroup } from "@coreai-ds/react-components";
import { Radio } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";

export const Intent = (): JSXElement => {
    const toasterId = useId('toaster');
    const { dispatchToast } = useToastController(toasterId);
    const [intent, setIntent] = React.useState<ToastIntent | 'progress' | 'avatar'>('success');
    const notify = () => {
        switch (intent) {
            case 'progress':
                dispatchToast(<Toast>
            <ToastTitle media={<Spinner size="tiny"/>}>Progress toast</ToastTitle>
          </Toast>);
                break;
            case 'avatar':
                dispatchToast(<Toast>
            <ToastTitle media={<Avatar name="Erika Mustermann" size={16}/>}>Avatar toast</ToastTitle>
          </Toast>);
                break;
            case 'error':
            case 'info':
            case 'success':
            case 'warning':
                dispatchToast(<Toast>
            <ToastTitle>Toast intent: {intent}</ToastTitle>
          </Toast>, { intent });
                break;
        }
    };
    return (<>
      <Field label="Select a intent">
        <RadioGroup value={intent} onChange={(e, data) => setIntent(data.value as ToastIntent)}>
          <Radio label="success" value="success"/>
          <Radio label="info" value="info"/>
          <Radio label="warning" value="warning"/>
          <Radio label="error" value="error"/>
          <Radio label="progress (custom media slot)" value="progress"/>
          <Radio label="avatar (custom media slot)" value="avatar"/>
        </RadioGroup>
      </Field>
      <Toaster toasterId={toasterId}/>
      <Button onClick={() => notify()}>Make toast</Button>
    </>);
};

export default Intent;

Inverted Appearance

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import { ToastBody } from "@coreai-ds/react-components";
import { ToastFooter } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import * as React from 'react';

export const InvertedAppearance = (): JSXElement => {
    const toasterId = useId('toaster');
    const { dispatchToast } = useToastController(toasterId);
    const notify = () => dispatchToast(<Toast appearance="inverted">
        <ToastTitle action={<Link>Undo</Link>}>Email sent</ToastTitle>
        <ToastBody subtitle="Subtitle">This is a toast body</ToastBody>
        <ToastFooter>
          <Link>Action</Link>
          <Link>Action</Link>
        </ToastFooter>
      </Toast>, { intent: 'success' });
    return (<>
      <Toaster toasterId={toasterId}/>
      <Button onClick={notify}>Make toast</Button>
    </>);
};

export default InvertedAppearance;

Multiple Toasters

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import * as React from 'react';
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { RadioGroup } from "@coreai-ds/react-components";
import { Radio } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";

export const MultipleToasters = (): JSXElement => {
    const first = useId('toaster-1');
    const second = useId('toaster-2');
    const [toaster, setToaster] = React.useState(first);
    const { dispatchToast: dispatchFirstToast } = useToastController(first);
    const { dispatchToast: dispatchSecondToast } = useToastController(second);
    const notify = () => {
        if (toaster === first) {
            dispatchFirstToast(<Toast>
          <ToastTitle>First toaster</ToastTitle>
        </Toast>, { intent: 'info' });
        }
        else {
            dispatchSecondToast(<Toast>
          <ToastTitle>Second toaster</ToastTitle>
        </Toast>, { intent: 'info' });
        }
    };
    return (<>
      <Field label="Choose toaster">
        <RadioGroup value={toaster} onChange={(e, data) => setToaster(data.value)}>
          <Radio label="First toaster" value={first}/>
          <Radio label="Second toaster" value={second}/>
        </RadioGroup>
      </Field>
      <Toaster toasterId={first} position="bottom-end"/>
      <Toaster toasterId={second} position="top-end"/>
      <Button onClick={notify}>Make toast</Button>
    </>);
};

export default MultipleToasters;

Offset

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import * as React from 'react';
import type { ToastPosition } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { SpinButton } from "@coreai-ds/react-components";
import { RadioGroup } from "@coreai-ds/react-components";
import { Radio } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    playground: {
        display: 'grid',
        gridTemplateColumns: '25% 75%',
        columnGap: '20px',
        rowGap: '20px',
    },
    horizontal: {
        gridColumnEnd: 2,
    },
    vertical: {
        gridRowStart: 2,
        gridColumnEnd: 2,
    },
    positions: {
        gridRowStart: 1,
        gridRowEnd: 3,
        gridColumnStart: 2,
    },
});

export const Offset = (): JSXElement => {
    const styles = useStyles();
    const toasterId = useId('toaster');
    const { dispatchToast } = useToastController(toasterId);
    const [horizontal, setHorizontal] = React.useState(20);
    const [vertical, setVertical] = React.useState(16);
    const [position, setPosition] = React.useState<ToastPosition>('bottom-end');
    const notify = () => dispatchToast(<Toast>
        <ToastTitle>
          Offset: {horizontal}, {vertical}
        </ToastTitle>
      </Toast>, { position, intent: 'info' });
    return (<>
      <div className={styles.playground}>
        <Field label="Horizontal offset" className={styles.horizontal}>
          <SpinButton value={horizontal} onChange={(e, data) => {
            if (data.value) {
                setHorizontal(data.value);
            }
            else if (data.displayValue !== undefined) {
                const newValue = parseFloat(data.displayValue);
                if (!Number.isNaN(newValue)) {
                    setHorizontal(newValue);
                }
            }
        }}/>
        </Field>
        <Field label="Vertical offset" className={styles.vertical}>
          <SpinButton value={vertical} onChange={(e, data) => {
            if (data.value) {
                setVertical(data.value);
            }
            else if (data.displayValue !== undefined) {
                const newValue = parseFloat(data.displayValue);
                if (!Number.isNaN(newValue)) {
                    setVertical(newValue);
                }
            }
        }}/>
        </Field>
        <Field label="Toast position" className={styles.positions}>
          <RadioGroup value={position} onChange={(e, data) => setPosition(data.value as ToastPosition)}>
            <Radio label="bottom" value="bottom"/>
            <Radio label="bottom-start" value="bottom-start"/>
            <Radio label="bottom-end" value="bottom-end"/>
            <Radio label="top" value="top"/>
            <Radio label="top-start" value="top-start"/>
            <Radio label="top-end" value="top-end"/>
          </RadioGroup>
        </Field>
      </div>
      <br />
      <Button onClick={() => notify()}>Make toast</Button>
      <Toaster toasterId={toasterId} offset={{ horizontal, vertical }}/>
    </>);
};

export default Offset;

Pause And Play

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import * as React from 'react';
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { ToggleButton } from "@coreai-ds/react-components";
import { PlayFilled } from "@fluentui/react-icons";
import { PauseFilled } from "@fluentui/react-icons";

export const PauseAndPlay = (): JSXElement => {
    const toasterId = useId('toaster');
    const toastId = useId('example');
    const [unmounted, setUnmounted] = React.useState(true);
    const [paused, setPaused] = React.useState(false);
    const { pauseToast, playToast, dispatchToast } = useToastController(toasterId);
    const notify = () => {
        dispatchToast(<Toast>
        <ToastTitle>This is a toast</ToastTitle>
      </Toast>, {
            toastId,
            intent: 'success',
            onStatusChange: (e, { status }) => {
                setUnmounted(status === 'unmounted');
                setPaused(false);
            },
        });
        setUnmounted(false);
    };
    const toggle = () => {
        if (paused) {
            playToast(toastId);
            setPaused(false);
        }
        else {
            pauseToast(toastId);
            setPaused(true);
        }
    };
    return (<>
      <Toaster toasterId={toasterId}/>
      <Button disabledFocusable={!unmounted} onClick={notify}>
        Make toast
      </Button>
      <ToggleButton icon={paused ? <PlayFilled /> : <PauseFilled />} disabledFocusable={unmounted} onClick={toggle} checked={paused}>
        {paused ? 'Play' : 'Pause'} toast
      </ToggleButton>
    </>);
};

export default PauseAndPlay;

Pause On Hover

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import * as React from 'react';

export const PauseOnHover = (): JSXElement => {
    const toasterId = useId('toaster');
    const { dispatchToast } = useToastController(toasterId);
    const notify = () => dispatchToast(<Toast>
        <ToastTitle>Hover me!</ToastTitle>
      </Toast>, { pauseOnHover: true, intent: 'info' });
    return (<>
      <Toaster toasterId={toasterId}/>
      <Button onClick={notify}>Make toast</Button>
    </>);
};

export default PauseOnHover;

Pause On Window Blur

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import * as React from 'react';

export const PauseOnWindowBlur = (): JSXElement => {
    const toasterId = useId('toaster');
    const { dispatchToast } = useToastController(toasterId);
    const notify = () => dispatchToast(<Toast>
        <ToastTitle>Click on another window!</ToastTitle>
      </Toast>, { pauseOnWindowBlur: true, intent: 'info' });
    return (<>
      <Toaster toasterId={toasterId}/>
      <Button onClick={notify}>Make toast</Button>
    </>);
};

export default PauseOnWindowBlur;

Progress Toast

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import * as React from 'react';
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { ToastTrigger } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import { ToastBody } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import { ProgressBar } from "@coreai-ds/react-components";
import { ToastFooter } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";

const intervalIncrement = 5;

const intervalDelay = 100;

const DownloadProgressBar: React.FC<{
    onDownloadEnd: () => void;
}> = ({ onDownloadEnd }) => {
    const [value, setValue] = React.useState(100);
    // This effect simulates progress value based on state/remote data
    React.useEffect(() => {
        if (value > 0) {
            const timeout = setTimeout(() => {
                setValue(v => Math.max(v - intervalIncrement, 0));
            }, intervalDelay);
            return () => clearTimeout(timeout);
        }
        if (value === 0) {
            onDownloadEnd();
        }
    }, [value, onDownloadEnd]);
    return <ProgressBar value={value} max={100}/>;
};

export const ProgressToast = (): JSXElement => {
    const toasterId = useId('toaster');
    const toastId = useId('toast');
    const [unmounted, setUnmounted] = React.useState(true);
    const { dispatchToast, dismissToast } = useToastController(toasterId);
    const dismiss = React.useCallback(() => dismissToast(toastId), [dismissToast, toastId]);
    const notify = () => dispatchToast(<Toast>
        <ToastTitle action={<ToastTrigger>
              <Link>Dismiss</Link>
            </ToastTrigger>}>
          Downloading file
        </ToastTitle>
        <ToastBody>
          <Text>This may take a while</Text>
          <DownloadProgressBar onDownloadEnd={dismiss}/>
        </ToastBody>
        <ToastFooter>
          <Link>Action</Link>
          <Link>Action</Link>
        </ToastFooter>
      </Toast>, {
        intent: 'success',
        timeout: -1,
        toastId,
        onStatusChange: (e, { status }) => setUnmounted(status === 'unmounted'),
    });
    return (<>
      <Toaster toasterId={toasterId}/>
      <Button disabledFocusable={!unmounted} onClick={notify}>
        Make toast
      </Button>
    </>);
};

export default ProgressToast;

Toast Lifecycle

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import * as React from 'react';
import type { ToastStatus } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import { ToastBody } from "@coreai-ds/react-components";
import { ToastFooter } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    root: {
        display: 'flex',
        gap: '20px',
    },
    button: {
        display: 'block',
    },
    logContainer: {
        display: 'flex',
        flexDirection: 'column',
    },
    logLabel: {
        color: tokens.colorNeutralForegroundOnBrand,
        backgroundColor: tokens.colorBrandBackground,
        width: 'fit-content',
        fontWeight: tokens.fontWeightBold,
        padding: '2px 12px',
    },
    log: {
        overflowY: 'auto',
        boxShadow: tokens.shadow16,
        position: 'relative',
        minWidth: '200px',
        height: '200px',
        border: `2px solid ${tokens.colorBrandBackground}`,
        padding: '12px',
    },
});

export const ToastLifecycle = (): JSXElement => {
    const styles = useStyles();
    const toasterId = useId('toaster');
    const labelId = useId();
    const { dispatchToast } = useToastController(toasterId);
    const [statusLog, setStatusLog] = React.useState<[
        number,
        ToastStatus
    ][]>([]);
    const [dismissed, setDismissed] = React.useState(true);
    const notify = () => {
        dispatchToast(<Toast>
        <ToastTitle action={<Link>Undo</Link>}>Email sent</ToastTitle>
        <ToastBody subtitle="Subtitle">This is a toast body</ToastBody>
        <ToastFooter>
          <Link>Action</Link>
          <Link>Action</Link>
        </ToastFooter>
      </Toast>, {
            timeout: 1000,
            intent: 'success',
            onStatusChange: (e, { status: toastStatus }) => {
                setDismissed(toastStatus === 'unmounted');
                setStatusLog(prev => [[Date.now(), toastStatus], ...prev]);
            },
        });
    };
    return (<>
      <div className={styles.root}>
        <div>
          <Button className={styles.button} disabledFocusable={!dismissed} onClick={notify}>
            Make toast
          </Button>
          <Button className={styles.button} onClick={() => setStatusLog([])}>
            Clear log
          </Button>
        </div>
        <div className={styles.logContainer}>
          <div className={styles.logLabel} id={labelId}>
            Status log
          </div>
          <div role="log" aria-labelledby={labelId} className={styles.log}>
            {statusLog.map(([time, toastStatus], i) => {
            const date = new Date(time);
            return (<div key={i}>
                  {date.toLocaleTimeString()} <Text weight="bold">{toastStatus}</Text>
                </div>);
        })}
          </div>
        </div>
      </div>
      <Toaster toasterId={toasterId}/>
    </>);
};

export default ToastLifecycle;

Toast Positions

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import * as React from 'react';
import type { ToastPosition } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { RadioGroup } from "@coreai-ds/react-components";
import { Radio } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";

export const ToastPositions = (): JSXElement => {
    const toasterId = useId('toaster');
    const { dispatchToast } = useToastController(toasterId);
    const [position, setPosition] = React.useState<ToastPosition>('top');
    const notify = () => dispatchToast(<Toast>
        <ToastTitle>This toast is {position}</ToastTitle>
      </Toast>, { position, intent: 'success' });
    return (<>
      <Field label="Select a position">
        <RadioGroup value={position} onChange={(e, data) => setPosition(data.value as ToastPosition)}>
          <Radio label="bottom" value="bottom"/>
          <Radio label="bottom-start" value="bottom-start"/>
          <Radio label="bottom-end" value="bottom-end"/>
          <Radio label="top" value="top"/>
          <Radio label="top-start" value="top-start"/>
          <Radio label="top-end" value="top-end"/>
        </RadioGroup>
      </Field>
      <Toaster toasterId={toasterId}/>
      <Button onClick={() => notify()}>Make toast</Button>
    </>);
};

export default ToastPositions;

Toaster Limit

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { useToastController } from "@coreai-ds/react-components";
import * as React from 'react';
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { SpinButton } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";

export const ToasterLimit = (): JSXElement => {
    const toasterId = useId('toaster');
    const { dispatchToast } = useToastController(toasterId);
    const [limit, setLimit] = React.useState(3);
    const notify = () => dispatchToast(<Toast>
        <ToastTitle>Limited to 3 toasts</ToastTitle>
      </Toast>, { intent: 'success' });
    return (<>
      <Field label="Toaster Limit">
        <SpinButton value={limit} onChange={(e, data) => {
            if (data.value) {
                setLimit(data.value);
            }
            else if (data.displayValue !== undefined) {
                const newValue = parseFloat(data.displayValue);
                if (!Number.isNaN(newValue)) {
                    setLimit(newValue);
                }
            }
        }}/>
      </Field>
      <br />
      <Toaster toasterId={toasterId} limit={limit}/>
      <Button onClick={notify}>Make toast</Button>
    </>);
};

export default ToasterLimit;

Update Toast

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import * as React from 'react';
import { useToastController } from "@coreai-ds/react-components";
import { Toast } from "@coreai-ds/react-components";
import { ToastTitle } from "@coreai-ds/react-components";
import { Toaster } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";

export const UpdateToast = (): JSXElement => {
    const toastId = useId('toast');
    const toasterId = useId('toaster');
    const [unmounted, setUnmounted] = React.useState(true);
    const { dispatchToast, updateToast } = useToastController(toasterId);
    const notify = () => {
        dispatchToast(<Toast>
        <ToastTitle>This toast never closes</ToastTitle>
      </Toast>, {
            toastId,
            intent: 'warning',
            timeout: -1,
            onStatusChange: (e, { status }) => setUnmounted(status === 'unmounted'),
        });
        setUnmounted(false);
    };
    const update = () => updateToast({
        content: (<Toast>
          <ToastTitle>This toast will close soon</ToastTitle>
        </Toast>),
        intent: 'success',
        toastId,
        timeout: 2000,
    });
    return (<>
      <Toaster toasterId={toasterId}/>
      <Button onClick={unmounted ? notify : update}>{unmounted ? 'Make toast' : 'Update toast'}</Button>
    </>);
};

export default UpdateToast;