- Components
Toast
A short message that appears at the bottom, from anywhere in the app, and leaves by itself.
npx shadcn add @klarhimmel/toast @klarhimmel/buttonWhen to use
Use for
Confirming what already happened: saved, copied, removed with Undo.
Not for
Errors or choices that need action. Use a Banner or a Dialog.
Pairs with
Button, a list with Undo.
Preview
Each toast leaves on its own, and stays while you point at it or focus it.
toast.tsx
import { Theme } from '@/components/klarhimmel/theme/style';
import { Button } from '@/components/klarhimmel/ui/button';
import { Toaster, toast } from '@/components/klarhimmel/ui/toast';
export default function Example() {
return (
<Theme theme="brand">
<Toaster />
<Button onClick={() => toast('Changes saved')}>Save</Button>
<Button
variant="secondary"
onClick={() => toast('Room removed', { action: { label: 'Undo', onClick: () => console.log('restore') } })}
>
Remove room
</Button>
</Theme>
);
}Install
Import
import { Toaster, toast, dismissToast, clearToasts } from '@/components/klarhimmel/ui/toast';- Lands in
- components/klarhimmel/ui/toast.tsx, plus cn() and the theme item if they are missing. Import theme.css after Tailwind.
- Render in
- Render it inside <Theme>, once near the root of your app. Tokens and fonts are scoped to it, so outside it the component is unstyled.
- Limit
- Overlays render into the Theme root with position: fixed. A transform on an ancestor re-parents fixed (a dialog centres in the wrapper) and overflow: hidden clips menus. Render <Theme> at the app root, outside any transformed wrapper.
Examples
Tones
Neutral and info are polite; danger is announced at once.
import { Button } from '@/components/klarhimmel/ui/button'; import { Toaster, toast } from '@/components/klarhimmel/ui/toast'; export default function ToastTones() { return ( <div className="flex min-h-20 flex-col items-start gap-3"> <div className="flex flex-wrap gap-3"> <Button variant="secondary" onClick={() => toast('Copied the booking link')}>Neutral</Button> <Button variant="secondary" onClick={() => toast('Prices updated', { tone: 'info', description: 'Three rooms changed.' })}>Info</Button> <Button variant="secondary" onClick={() => toast('Could not sync the calendar', { tone: 'danger', description: 'Try again in a minute.' })}>Danger</Button> </div> <p className="text-kh-small text-kh-muted">Neutral and info are polite; danger is announced at once.</p> <Toaster /> </div> ); }Action
- Seaside suite
- Garden room
import { useState } from 'react'; import { Button } from '@/components/klarhimmel/ui/button'; import { Toaster, toast } from '@/components/klarhimmel/ui/toast'; export default function ToastAction() { const [rooms, setRooms] = useState(['Seaside suite', 'Garden room']); const remove = (room: string) => { const at = rooms.indexOf(room); setRooms((r) => r.filter((x) => x !== room)); toast(`${room} removed`, { action: { label: 'Undo', onClick: () => setRooms((r) => [...r.slice(0, at), room, ...r.slice(at)]) }, }); }; return ( <div className="flex min-h-20 flex-col items-start gap-3"> <ul className="flex flex-col gap-2"> {rooms.map((r) => ( <li key={r} className="flex items-center gap-3 text-kh-small"> {r} <Button size="sm" variant="ghost" onClick={() => remove(r)}>Remove</Button> </li> ))} {!rooms.length && <li className="text-kh-small text-kh-muted">No rooms left.</li>} </ul> <Toaster /> </div> ); }
API reference
| Prop | Type | Default | Description |
|---|---|---|---|
toast(title, options) | (title: string, options?) => number | - | Shows a toast and returns its id. At most three are kept. |
options.tone | 'neutral' | 'info' | 'danger' | 'neutral' | Danger is announced at once (role=alert). |
options.description | string | - | A second line. |
options.action | { label: string; onClick: () => void } | - | One next step like Undo. A toast with an action is not replaced by a later one. |
options.duration | number | 5000 | Milliseconds; 0 keeps it until dismissed. A toast with an action stays until dismissed unless you set one. It never leaves while hovered or focused. |
Toaster label | string | 'Notifications' | Accessible name of the region. |
dismissToast(id), clearToasts() | - | - | Remove one toast or all of them. |
Accessibility
| Key | Does |
|---|---|
Tab | Moves to a toast's action and its close button |
Enter / Space | Runs the action or dismisses |
Escape | Dismisses the toast that has focus |
A toast stays while it is hovered or focused. Danger toasts are announced at once; the others politely.
Accessibility