Skip to main content

Toast

Toast is a notification component for brief messages, like confirming a saved change or offering to undo an action. It shows the notifications you send with useToast and queues them at six screen positions.

Import

import { ToastProvider } from '@vortexlabs/vortex';
import type { ToastProviderProps } from '@vortexlabs/vortex';

Allied components

Other links

Features

  • Shows and hides notifications with useToast.
  • Supports six tones and two layouts.
  • Supports icons, descriptions, and actions.
  • Supports six positions with separate queues.
  • Pauses auto-dismiss on hover and focus.

Showing Toasts

VortexProvider already includes ToastProvider, so no setup is needed. Get show from useToast and pass it the notification's title and description.

"use client";

import { Button, useToast } from "@vortexlabs/vortex";

export const ToastExample = () => {
  const toast = useToast();

  return (
    <Button
      onClick={() =>
        toast.show({
          title: "Changes saved",
          description: "Your project is up to date.",
          tone: "success",
        })
      }
    >
      Save changes
    </Button>
  );
};

Tones and Icons

Set tone to match the message; the default is inverse. Add icon for a visual cue.

"use client";

import { Button, Stack, useToast } from "@vortexlabs/vortex";
import { CircleInformation } from "@vortexlabs/vortex-icons";

export const ToastTonesExample = () => {
  const toast = useToast();

  return (
    <Stack direction="row" gap={3} wrap>
      {(["inverse", "neutral", "info", "success", "warning", "error"] as const).map(
        (tone) => (
          <Button
            key={tone}
            variant="secondary"
            onClick={() =>
              toast.show({
                title: `${tone} notification`,
                tone,
                icon: CircleInformation,
              })
            }
          >
            {tone}
          </Button>
        ),
      )}
    </Stack>
  );
};

Duration

The default timeout is "brief" (4 seconds). Use "extended" (8 seconds) or a number of milliseconds.

"use client";

import { Button, Stack, useToast } from "@vortexlabs/vortex";

export const ToastDurationExample = () => {
  const toast = useToast();

  return (
    <Stack direction="row" gap={3} wrap>
      <Button
        variant="secondary"
        onClick={() => toast.show({ title: "Link copied", timeout: "brief" })}
      >
        Show brief notification
      </Button>
      <Button
        variant="secondary"
        onClick={() =>
          toast.show({
            title: "Draft saved",
            description: "You can keep editing or publish it later.",
            timeout: "extended",
          })
        }
      >
        Show extended notification
      </Button>
    </Stack>
  );
};

Actions

Pass one button or an array to actionsSlot. The last is primary in inline layout, the first in stacked.

Pass the ID from show to hide to close it from an action. timeout: 0 keeps it open until then.

Project: Active
"use client";

import { Button, Stack, Text, useToast } from "@vortexlabs/vortex";
import { useState } from "react";

export const ToastActionsExample = () => {
  const toast = useToast();
  const [toastId, setToastId] = useState<string | null>(null);

  const restore = (id: string) => {
    toast.hide(id);
    setToastId(null);
  };

  const archive = () => {
    const id = toast.show({
      title: "Project archived",
      description: "You can restore it from the archive at any time.",
      layout: "stacked",
      timeout: 0,
      actionsSlot: [
        <Button key="undo" onClick={() => restore(id)}>
          Undo
        </Button>,
        <Button key="dismiss" onClick={() => toast.hide(id)}>
          Dismiss
        </Button>,
      ],
    });
    setToastId(id);
  };

  return (
    <Stack gap={3} align="start">
      <Text>Project: {toastId ? "Archived" : "Active"}</Text>
      <Button
        variant="secondary"
        onClick={() => (toastId ? restore(toastId) : archive())}
      >
        {toastId ? "Restore project" : "Archive project"}
      </Button>
    </Stack>
  );
};

Position

The default position is bottom-end. start and end follow the text direction.

"use client";

import { Button, Stack, useToast } from "@vortexlabs/vortex";

export const ToastPositionExample = () => {
  const toast = useToast();

  return (
    <Stack direction="row" gap={3} wrap>
      {(
        [
          "top-start",
          "top-center",
          "top-end",
          "bottom-start",
          "bottom-center",
          "bottom-end",
        ] as const
      ).map((position) => (
        <Button
          key={position}
          variant="secondary"
          onClick={() => toast.show({ title: `Notification at ${position}`, position })}
        >
          {position}
        </Button>
      ))}
    </Stack>
  );
};

Separate Queues

A nested ToastProvider has its own queue and shows notifications inside its nearest positioned ancestor. useToast uses the closest provider.

options sets each position's width or keeps it expanded. Expanded stacks don't auto-dismiss, so add a dismiss action. For the app's provider, use toastOptions on VortexProvider.

"use client";

import { Button, Stack, ToastProvider, useToast } from "@vortexlabs/vortex";

const QueueButton = () => {
  const toast = useToast();

  const notify = () => {
    const id = toast.show({
      title: "Workspace updated",
      description: "Notification from the local queue.",
      position: "bottom-center",
      actionsSlot: <Button onClick={() => toast.hide(id)}>Dismiss</Button>,
    });
  };

  return (
    <Button variant="secondary" onClick={notify}>
      Add local notification
    </Button>
  );
};

export const ToastQueueExample = () => {
  return (
    <Stack
      width="100%"
      height="18rem"
      align="start"
      attributes={{ style: { position: "relative" } }}
    >
      <ToastProvider
        options={{ "bottom-center": { width: "min(22rem, 100%)", expanded: true } }}
      >
        <QueueButton />
      </ToastProvider>
    </Stack>
  );
};

Accessibility

Key
Description
Tab
Moves from the trigger into the notification's actions. Focus returns to the trigger on close.
EnterSpace
Expands or collapses the stack. Expanded stacks pause auto-dismiss.
warning and error notifications use role="alert"; other tones use role="status".
Give timeout: 0 notifications an action that calls hide.
Keep essential information outside temporary notifications.