Skip to content
Components

Toast

A brief status message that appears without interrupting the current task.

    Playground

    scheme

    Sets the semantic color treatment of the toast.

    duration

    Milliseconds the toast remains open before dismissing.

    Usage

    tsx
    import {
      Toast,
      ToastAction,
      ToastClose,
      ToastDescription,
      ToastProvider,
      ToastTitle,
      ToastViewport,
    } from "earthling-ui/toast";
    
    export function Example() {
      return (
        <>
          <ToastProvider>
            <Toast defaultOpen>
              <ToastTitle>Changes saved</ToastTitle>
              <ToastDescription>
                Your workspace preferences are up to date.
              </ToastDescription>
              <ToastAction altText="Undo saved changes">Undo</ToastAction>
              <ToastClose />
            </Toast>
            <ToastViewport />
          </ToastProvider>
        </>
      );
    }
    
    • Keep messages concise and use ToastAction only for a relevant recovery action such as Undo.
    • ToastAction requires altText so assistive technology can describe the action in context.
    • Do not rely on a toast for errors or decisions that require acknowledgment.

    Installation

    Start with the project setup for React and Tailwind CSS 4. Both paths use the same component and theme.

    bash
    npm install earthling-ui

    Use the component import shown above. Package updates keep the implementation current.

    API reference

    Declarations from the current library build, including inherited primitive props. Playground controls above show selected options; they are not the complete API.

    tsx
    // Generated by dts-bundle-generator v9.5.1
    
    import * as ToastPrimitive from '@radix-ui/react-toast';
    import { VariantProps } from 'class-variance-authority';
    import { ComponentPropsWithoutRef } from 'react';
    
    export declare const ToastProvider: import("react").FC<ToastPrimitive.ToastProviderProps>;
    export declare const ToastViewport: import("react").ForwardRefExoticComponent<Omit<ToastPrimitive.ToastViewportProps & import("react").RefAttributes<HTMLOListElement>, "ref"> & import("react").RefAttributes<HTMLOListElement>>;
    export declare const toastVariants: (props?: ({
    	scheme?: "default" | "primary" | "secondary" | "tertiary" | "neutral" | "muted" | "good" | "caution" | "bad" | null | undefined;
    } & import("class-variance-authority/types").ClassProp) | undefined) => string;
    export interface ToastProps extends ComponentPropsWithoutRef<typeof ToastPrimitive.Root>, VariantProps<typeof toastVariants> {
    }
    export declare const Toast: import("react").ForwardRefExoticComponent<ToastProps & import("react").RefAttributes<HTMLLIElement>>;
    export declare const ToastAction: import("react").ForwardRefExoticComponent<Omit<ToastPrimitive.ToastActionProps & import("react").RefAttributes<HTMLButtonElement>, "ref"> & import("react").RefAttributes<HTMLButtonElement>>;
    export declare const ToastClose: import("react").ForwardRefExoticComponent<Omit<ToastPrimitive.ToastCloseProps & import("react").RefAttributes<HTMLButtonElement>, "ref"> & import("react").RefAttributes<HTMLButtonElement>>;
    export declare const ToastTitle: import("react").ForwardRefExoticComponent<Omit<ToastPrimitive.ToastTitleProps & import("react").RefAttributes<HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
    export declare const ToastDescription: import("react").ForwardRefExoticComponent<Omit<ToastPrimitive.ToastDescriptionProps & import("react").RefAttributes<HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
    
    export {};

    Runtime dependencies: @radix-ui/react-toast, class-variance-authority, cnfast.

    Source

    Use the eject command to copy this implementation with its required helpers and project-specific imports.

    View Toast implementation
    tsx
    "use client";
    
    import {
      type ComponentPropsWithoutRef,
      type ComponentRef,
      forwardRef,
    } from "react";
    import * as ToastPrimitive from "@radix-ui/react-toast";
    import { cva, type VariantProps } from "class-variance-authority";
    import { cn } from "@/utils/cn";
    
    const ToastProvider = ToastPrimitive.Provider;
    
    const ToastViewport = forwardRef<
      ComponentRef<typeof ToastPrimitive.Viewport>,
      ComponentPropsWithoutRef<typeof ToastPrimitive.Viewport>
    >(({ className, ...props }, ref) => (
      <ToastPrimitive.Viewport
        ref={ref}
        className={cn(
          "fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:end-0 sm:top-auto sm:flex-col md:max-w-[420px]",
          className,
        )}
        {...props}
      />
    ));
    ToastViewport.displayName = ToastPrimitive.Viewport.displayName;
    
    const toastVariants = cva(
      "group pointer-events-auto relative flex w-full items-center justify-between gap-2 overflow-hidden rounded-xl border p-4 pe-12 shadow-lg transition-[transform,translate,opacity] duration-200 ease-out data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-(--radix-toast-swipe-end-x) data-[swipe=move]:translate-x-(--radix-toast-swipe-move-x) data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full motion-reduce:animate-none motion-reduce:transition-none",
      {
        variants: {
          scheme: {
            default: "border bg-background text-foreground",
            primary: "border-primary/50 bg-primary text-primary-foreground",
            secondary: "border-secondary/50 bg-secondary text-secondary-foreground",
            tertiary: "border-tertiary/50 bg-tertiary text-tertiary-foreground",
            neutral: "border-neutral/50 bg-neutral text-neutral-foreground",
            muted: "border-muted/50 bg-muted text-muted-foreground",
            good: "border-good/50 bg-good text-good-foreground",
            caution: "border-caution/50 bg-caution text-caution-foreground",
            bad: "border-bad/50 bg-bad text-bad-foreground",
          },
        },
        defaultVariants: {
          scheme: "default",
        },
      },
    );
    
    export interface ToastProps
      extends
        ComponentPropsWithoutRef<typeof ToastPrimitive.Root>,
        VariantProps<typeof toastVariants> {}
    
    const Toast = forwardRef<ComponentRef<typeof ToastPrimitive.Root>, ToastProps>(
      ({ className, scheme, ...props }, ref) => {
        return (
          <ToastPrimitive.Root
            ref={ref}
            className={cn(toastVariants({ scheme }), className)}
            {...props}
          />
        );
      },
    );
    Toast.displayName = ToastPrimitive.Root.displayName;
    
    const ToastAction = forwardRef<
      ComponentRef<typeof ToastPrimitive.Action>,
      ComponentPropsWithoutRef<typeof ToastPrimitive.Action>
    >(({ className, ...props }, ref) => (
      <ToastPrimitive.Action
        ref={ref}
        className={cn(
          "inline-flex h-8 shrink-0 items-center justify-center rounded-lg border bg-transparent px-3 text-sm font-medium hover:bg-current/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-outline disabled:pointer-events-none disabled:opacity-50",
          className,
        )}
        {...props}
      />
    ));
    ToastAction.displayName = ToastPrimitive.Action.displayName;
    
    const ToastClose = forwardRef<
      ComponentRef<typeof ToastPrimitive.Close>,
      ComponentPropsWithoutRef<typeof ToastPrimitive.Close>
    >(({ className, ...props }, ref) => (
      <ToastPrimitive.Close
        ref={ref}
        className={cn(
          "absolute end-1 top-1 flex size-10 items-center justify-center rounded-lg text-current opacity-70 hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-outline group-hover:opacity-100",
          className,
        )}
        {...props}
      >
        <i className="size-4 icon-[lucide--x]" aria-hidden="true" />
        <span className="sr-only">Close</span>
      </ToastPrimitive.Close>
    ));
    ToastClose.displayName = ToastPrimitive.Close.displayName;
    
    const ToastTitle = forwardRef<
      ComponentRef<typeof ToastPrimitive.Title>,
      ComponentPropsWithoutRef<typeof ToastPrimitive.Title>
    >(({ className, ...props }, ref) => (
      <ToastPrimitive.Title
        ref={ref}
        className={cn("text-sm font-semibold [&+div]:text-xs", className)}
        {...props}
      />
    ));
    ToastTitle.displayName = ToastPrimitive.Title.displayName;
    
    const ToastDescription = forwardRef<
      ComponentRef<typeof ToastPrimitive.Description>,
      ComponentPropsWithoutRef<typeof ToastPrimitive.Description>
    >(({ className, ...props }, ref) => (
      <ToastPrimitive.Description
        ref={ref}
        className={cn("text-sm opacity-90", className)}
        {...props}
      />
    ));
    ToastDescription.displayName = ToastPrimitive.Description.displayName;
    
    export {
      ToastProvider,
      ToastViewport,
      Toast,
      ToastTitle,
      ToastDescription,
      ToastClose,
      ToastAction,
      toastVariants,
    };