Lattice components

Toast

Queued notification primitive that owns scheduling, visibility limits, and exit timing while you own the toast surface and its parts.

@lattice-ui/toast Stable direction import Toast depends on core , layer , motion

Toast is the primitive for transient, non-blocking notifications: saved-changes confirmations, reward pop-ups, connection warnings, and inline status messages. A Provider owns the queue — enqueuing, the visible-count limit, per-toast duration, and exit timing — so your component only renders the surface for each toast and reacts to actions.

Reach for Toast when messages should stack and expire on their own, stay capped to a few at a time, and animate out without you tracking timers by hand. You drive it imperatively with the useToast hook from anywhere inside the provider.

Import

import { Toast, useToast } from "@lattice-ui/toast";

Anatomy

Provider and Viewport form the minimum system: the provider owns the queue and the viewport renders it. Viewport renders a default surface for every visible toast out of the box, so you only reach for Root, Title, Description, Action, and Close when you compose your own toast layout.

Toast anatomy
<Toast.Provider>
<Toast.Viewport>
<Toast.Root>
<Toast.Title />
<Toast.Description />
<Toast.Action />
<Toast.Close />
</Toast.Root>
</Toast.Viewport>
</Toast.Provider>
PartRequiredResponsibility
Toast.ProvideryesOwns the queue, default duration, visible cap, and exit timing; exposes useToast.
Toast.ViewportyesStacks visible toasts; renders a default surface per toast unless asChild.
Toast.RootnoA single toast surface that animates between visible and hidden.
Toast.TitlenoThe toast heading.
Toast.DescriptionnoThe toast supporting text.
Toast.ActionnoA button that runs onAction when activated.
Toast.ClosenoA button that runs onClose when activated.

Example

A provider at the top of the UI plus a button that enqueues toasts. The default Viewport stacks each queued toast’s surface automatically, so you only choose where the stack sits.

SaveStatusToasts.tsx
import { Toast, useToast } from "@lattice-ui/toast";
function SaveButton() {
const toast = useToast();
return (
<textbutton
Size={UDim2.fromOffset(140, 38)}
Text="Save layout"
Event={{
Activated: () =>
toast.enqueue({
title: "Layout saved",
description: "Your changes are live for everyone.",
durationMs: 3000,
}),
}}
/>
);
}
export function SaveStatusToasts() {
return (
<Toast.Provider defaultDurationMs={4000} maxVisible={3}>
<SaveButton />
<frame
AnchorPoint={new Vector2(1, 1)}
BackgroundTransparency={1}
Position={UDim2.new(1, -16, 1, -16)}
Size={UDim2.fromOffset(340, 320)}
>
<Toast.Viewport />
</frame>
</Toast.Provider>
);
}

To render a fully custom toast surface, set asChild on Viewport and map the queue yourself with useToast().visibleToasts, composing Toast.Root, Toast.Title, Toast.Action, and Toast.Close by hand. Wire each Toast.Close to remove(toast.id).

How it behaves

The queue

Toast.Provider keeps an ordered queue of records. enqueue(options) appends a toast and returns its id (auto-generated as toast-N unless you pass id). remove(id) starts a toast’s exit, and clear() empties the queue immediately. The provider runs a RunService.Heartbeat connection while any toasts exist, pruning expired ones each frame, and disconnects once the queue drains.

Visibility limit

maxVisible (default 3) caps how many toasts are rendered at once; the rest wait in the queue. useToast().visibleToasts is the capped slice the viewport renders, while toasts is the full queue. Toasts beyond the cap do not start their duration countdown until they enter the visible window.

Duration and expiry

Each toast expires after its own durationMs, falling back to the provider’s defaultDurationMs (default 4000). A duration of 0 or less makes a toast sticky — it never expires on its own and must be removed via remove, Toast.Close, or clear. When a visible toast’s time elapses, the provider marks it exiting and keeps it around for a short exit window (~160 ms) so its motion can finish before it is dropped.

Motion and presence

Toast.Root animates its background between an active (opaque) and inactive (transparent) state based on visible, using a default response recipe. The default Viewport wires visible to each toast’s non-exiting state, so toasts fade as they leave. Override the recipe per root with transition.

API reference

Toast.Provider

Prop Type Description
defaultDurationMs number Fallback lifetime for toasts without their own durationMs. Clamped to >= 0. Defaults to 4000.
maxVisible number Maximum toasts rendered at once; the rest queue. Clamped to >= 1. Defaults to 3.
children React.ReactNode The UI tree that enqueues toasts and renders the viewport.

useToast

Returns the imperative API for the nearest provider.

Prop Type Description
toasts Array<ToastRecord> The full queue, including toasts beyond the visible cap.
visibleToasts Array<ToastRecord> The capped slice currently eligible to render.
enqueue (options: ToastOptions) => string Adds a toast and returns its id.
remove (id: string) => void Starts the exit for the matching toast.
clear () => void Removes every toast immediately.

ToastOptions accepts id, title, description, and durationMs — all optional.

Toast.Viewport

Prop Type Description
asChild boolean Render the single child element instead of the default stacking frame and per-toast surfaces. You then map the queue yourself.
children React.ReactNode Extra content appended after the rendered toasts, or the single element when asChild is set.

Toast.Root

Prop Type Description
visible boolean Drives the active/inactive motion state. Defaults to true.
transition MotionConfig Overrides the default toast response recipe used for the show/hide animation.
asChild boolean Apply the visibility and motion ref to the single child element instead of the default frame.
children React.ReactNode The toast contents.

Toast.Title

Prop Type Description
asChild boolean Render the single child element instead of the default textlabel.
children React.ReactElement The element to render. Required when asChild is set.

Toast.Description

Prop Type Description
asChild boolean Render the single child element instead of the default textlabel.
children React.ReactElement The element to render. Required when asChild is set.

Toast.Action

Prop Type Description
onAction () => void Called when the action button is activated.
asChild boolean Merge the activation behavior onto the single child element instead of the default textbutton.
children React.ReactElement The element to render. Required when asChild is set.

Toast.Close

Prop Type Description
onClose () => void Called when the close button is activated. Wire this to remove(id).
asChild boolean Merge the activation behavior onto the single child element instead of the default textbutton.
children React.ReactElement The element to render. Required when asChild is set.