Toast
Toast is a neobrutalist React component from Cruise UI. Feedback that pops up in a corner or edge you choose (bottom-right by default): copied, saved, something went wrong. Install it with npx shadcn@latest add @cruiseui/toast.
Install
Terminal
npx shadcn@latest add @cruiseui/toastFirst time? Installation shows the one-off components.json setup (the @cruiseui registry) and how to turn the theme on.
Example
Corners
Something went wrong
Try again.
"use client";
import { CruiseButton } from "@/components/cruise/button";
import { CruiseToast } from "@/components/cruise/toast";
import { CruiseToaster, useCruiseToast } from "@/components/cruise/toaster";
function SaveButtons() {
const { toast } = useCruiseToast();
return (
<div className="flex flex-wrap gap-3">
<CruiseButton variant="secondary" onClick={() => toast({ tone: "success", title: "Saved", description: "Your changes are live." })}>
Save changes
</CruiseButton>
{/* One toast can go somewhere else. */}
<CruiseButton
variant="secondary"
onClick={() => toast({ tone: "info", title: "Copied", description: "Link copied.", position: "bottom-center" })}
>
Copy link
</CruiseButton>
</div>
);
}
export default function ToastExample() {
return (
// Wrap your app once; position: top-left | top-center | top-right |
// bottom-left | bottom-center | bottom-right (default).
<CruiseToaster position="top-right">
<div className="flex flex-col gap-6">
<SaveButtons />
<CruiseToast tone="danger" title="Something went wrong">
Try again.
</CruiseToast>
</div>
</CruiseToaster>
);
}
<div class="toast-viewport" data-position="top-right">
<div class="toast brutal" role="status" style="display: flex; overflow: hidden">
<span style="width: 8px; background: var(--success)"></span>
<div style="padding: 12px 16px"><strong>Done!</strong><br>Your ticket has been sent.</div>
</div>
</div>Needs theme.css. Interactive parts (menus, tabs, drawers) also need the script in the spec for that component.
When to use it
When to use
All feedback after an action. Auto-dismiss after ~3s; errors stay until closed.
When not to
Information people need to act on later (put it on the page). Never use alert().
Props
CruiseToast
| Prop | Type | Default | Description |
|---|---|---|---|
tone? | CruiseToastTone | "info" | — |
title | ReactNode | — | — |
children? | ReactNode | — | — |
onDismiss? | (() => void) | — | — |
className? | string | — | — |
CruiseToaster
| Prop | Type | Default | Description |
|---|---|---|---|
position? | CruiseToastPosition | "bottom-right" | Default spot for every toast; each toast can override it. |
children? | ReactNode | — | — |
CruiseToastViewport
| Prop | Type | Default | Description |
|---|---|---|---|
position? | CruiseToastPosition | "bottom-right" | Where the stack sits. |
children | ReactNode | — | — |
Usage
- Wrap your app in CruiseToaster once, then call useCruiseToast().toast({ title, description, tone, position }) anywhere.
- position is top-left, top-center, top-right, bottom-left, bottom-center or bottom-right (the default). Set it on the Toaster for every toast, or on one toast to override it.
- Top stacks grow down with the newest on top; bottom stacks grow up with the newest at the bottom. Below 640px every position is full width with 16px gutters.
- For your own toast (e.g. CruiseAchievementToast), pass render: (dismiss) => <YourToast onDismiss={dismiss} />.
Accessibility
- role="status" (role="alert" for danger), so screen readers announce it.
- The coloured left bar is backed by a title (Done!, Something went wrong).
- Errors stay until closed; under reduced motion toasts fade instead of sliding.