Toast
A brief status message that appears without interrupting the current task.
Preview
Example code
Playground
schemeSets the semantic color treatment of the toast.
durationMilliseconds 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.
Import package
Own the source
bash
npm install earthling-uiUse 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,
};