Primitives
Toast
Tone icons in tiles, a tone wash, promises with a spinner. Nine positions: every corner and edge, and the middle of the screen.
Pick a spot on the screen.
toast("…", { position: "bottom-right" }) · or <Toaster position="bottom-right" />toast.tsx
"use client";
import { Button, Toaster, toast, type ToastPosition } from "@waveinno/ui";
import * as React from "react";
function ToastKinds() {
return (
<div className="flex flex-wrap gap-2">
<Button variant="secondary" onClick={() => toast("Session started", { description: "DHA-GA 12-3456 entered at Gate 1." })}>
Default
</Button>
<Button variant="secondary" onClick={() => toast.success("Payout sent", { description: "৳1,24,500 to the account ending 4410." })}>
Success
</Button>
<Button variant="secondary" onClick={() => toast.error("Payment failed", { description: "bKash declined: wallet limit reached." })}>
Error
</Button>
<Button variant="secondary" onClick={() => toast.warning("Gate 2 is slow", { description: "Plates are taking 4 s to read." })}>
Warning
</Button>
<Button variant="secondary" onClick={() => toast.info("Rates change on 1 November")}>
Info
</Button>
<Button
variant="secondary"
onClick={() => toast("Session voided", { description: "Receipt #1042 is cancelled.", action: { label: "Undo", onClick: () => toast.success("Restored") } })}
>
With action
</Button>
<Button
onClick={() =>
toast.promise(new Promise((r) => setTimeout(r, 1800)), {
loading: "Exporting 2,431 sessions…",
success: "Export ready",
error: "Export failed",
})
}
>
Promise
</Button>
</div>
);
}
const SPOTS: { position: ToastPosition; label: string }[] = [
{ position: "top-left", label: "Top left" },
{ position: "top-center", label: "Top" },
{ position: "top-right", label: "Top right" },
{ position: "middle-left", label: "Middle left" },
{ position: "middle-center", label: "Centre" },
{ position: "middle-right", label: "Middle right" },
{ position: "bottom-left", label: "Bottom left" },
{ position: "bottom-center", label: "Bottom" },
{ position: "bottom-right", label: "Bottom right" },
];
function ToastPositions() {
const [last, setLast] = React.useState<ToastPosition>("bottom-right");
const fire = (p: ToastPosition, label: string) => {
setLast(p);
const opts = { description: `position="${p}"` };
if (p.startsWith("middle-")) toast.success(`${label}`, { ...opts, toasterId: p });
else toast.success(`${label}`, { ...opts, position: p as Exclude<ToastPosition, `middle-${string}`> });
};
return (
<div className="space-y-3">
<p className="text-[12px] text-muted">Pick a spot on the screen.</p>
<div className="grid max-w-md grid-cols-3 gap-2 rounded-[calc(16px*var(--radius-scale))] border border-border bg-surface p-2 shadow-[inset_0_1px_3px_rgba(5,8,22,.06)]">
{SPOTS.map((s) => (
<button
key={s.position}
type="button"
onClick={() => fire(s.position, s.label)}
className={
"group relative grid h-16 cursor-pointer place-items-center rounded-[calc(11px*var(--radius-scale))] border text-[12px] font-medium outline-none transition-[background-color,border-color,color,box-shadow,transform] duration-200 active:scale-95 focus-visible:ring-2 focus-visible:ring-primary/40 " +
(last === s.position
? "border-primary bg-raised text-primary shadow-[0_0_0_3px_var(--primary-subtle)]"
: "border-border bg-raised/70 text-muted hover:border-border2 hover:bg-raised hover:text-text")
}
>
{s.label}
</button>
))}
</div>
<code className="block font-mono text-[12px] text-muted">
{last.startsWith("middle-") ? `<Toaster id="${last}" position="${last}" /> · toast("…", { toasterId: "${last}" })` : `toast("…", { position: "${last}" }) · or <Toaster position="${last}" />`}
</code>
{/* Toasters of their own for the middle of the screen. */}
<Toaster id="middle-left" position="middle-left" />
<Toaster id="middle-center" position="middle-center" />
<Toaster id="middle-right" position="middle-right" />
</div>
);
}
export default function ToastDemo() {
return (
<div className="space-y-8">
<ToastKinds />
<ToastPositions />
</div>
);
}Import#
Everything comes from the package root. The example above uses:
your-component.tsx
import { Button, Toaster, toast, type ToastPosition } from "@waveinno/ui";Props#
Read from the source of this version, so they match the code exactly.
<Toaster>
src/components/ui/toast.tsx| Prop | Type | Default | Description |
|---|---|---|---|
position | "top-left" | "top-center" | "top-right" | "middle-left" | "middle-center" | "middle-right" | "bottom-left" | "bottom-center" | "bottom-right" | "bottom-right" |
Also takes Omit<React.ComponentProps<typeof Sonner>, "position">.
<Button>
src/components/ui/button.tsx| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | |
loading | boolean | — |
Also takes ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof buttonVariants>.
Install#
If the project does not have the package yet, add it, then follow the setup for Next.js or Vite once.
$ npm install @waveinno/ui