Toaster
Where toasts appear: short messages that come and go on their own.
Preview
tsx
import { Button, Toaster, toast } from '@kerf-js/veneer'export function Basic() { return ( <> <Button onClick={() => toast.show({ title: 'Saved', description: 'Your changes are live.', }) } > Save changes </Button> <Toaster /> </> )}Installation
npm install @kerf-js/veneerTry it
Change the controls: the preview and its code update together. The address keeps what you set, so you can link to it.
Live preview
Controls
Tone
Codeupdates as you change the controls
import { Toaster } from '@kerf-js/veneer'toast.show({ title, description, tone, action })<Toaster />Usage
tsx
import { Toaster } from '@kerf-js/veneer'Tones
Each tone brings its own icon.
tsx
import { Button, Toaster, toast } from '@kerf-js/veneer'export function Tones() { return ( <> {TONES.map((tone) => ( <Button key={tone} emphasis="outline" tone={tone} onClick={() => toast.show({ title: 'Deploy finished', tone }) } > {tone} </Button> ))} <Toaster /> </> )}const TONES = [ 'neutral', 'positive', 'info', 'caution', 'critical',] as constPosition
Use position on Toaster to pick the corner.
tsx
import { state } from '@kerf-js/core'import { Button, Grid, Toaster, toast} from '@kerf-js/veneer'export function Position() { const position = state<(typeof CORNERS)[number]>('bottom-right') const show = (corner: (typeof CORNERS)[number]) => { position.value = corner toast.show({ title: 'Deploy finished', description: `Shown ${corner.replace('-', ' ')}.`, }) } return ( <> <Grid cols={3} gap="tight" > {CORNERS.map((corner) => ( <Button key={corner} emphasis="outline" tone="neutral" onClick={() => show(corner)} > {corner} </Button> ))} </Grid> <Toaster position={position.value} /> </> )}const CORNERS = [ 'top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', 'bottom-right',] as constWith an action
An action gives people ten seconds to take it.
tsx
import { state } from '@kerf-js/core'import { Button, Toaster, toast } from '@kerf-js/veneer'export function Undo() { const archived = state(false) const archive = () => { archived.value = true toast.show({ title: 'reports archived', action: { label: 'Undo', onClick: () => (archived.value = false), }, }) } return ( <> <Button emphasis="outline" tone="neutral" disabled={archived.value} onClick={archive} > {archived.value ? 'Archived' : 'Archive reports'} </Button> <Toaster /> </> )}Following a promise
toast.promise shows one toast from pending to done, in place.
tsx
import { Button, Toaster, toast } from '@kerf-js/veneer'export const Promise = () => { const deploy = () => toast.promise(wait(2200), { pending: { title: 'Deploying storefront', description: 'This takes about two seconds.', }, done: { title: 'storefront is live', description: 'Serving 9f3ac21 in eu-west.', }, error: 'The deploy failed', }) return ( <> <Button icon="rocket" onClick={deploy} > Deploy </Button> <Toaster /> </> )}const wait = (ms: number) => new Promise((done) => { setTimeout(done, ms) })Several at once
Three stack up, and fan out on hover. Hovering pauses every timer.
tsx
import { Button, Toaster, toast } from '@kerf-js/veneer'export const Several = () => { const many = () => [ 'eu-west', 'us-east', 'ap-south', 'eu-north', ].forEach((region, i) => setTimeout( () => toast.show({ title: `${region} is up to date`, tone: 'positive', }), i * 250, ), ) return ( <> <Button emphasis="outline" tone="neutral" onClick={many} > Roll out to four regions </Button> <Toaster /> </> )}Closing from code
duration: 0 keeps it up until toast.dismiss with the id toast.show returned.
tsx
import { state } from '@kerf-js/core'import { Button, Toaster, toast } from '@kerf-js/veneer'export function Dismissed() { const id = state('') const start = () => (id.value = toast.show({ title: 'Watching for failures', description: 'This stays until you stop it.', duration: 0, })) const stop = () => { toast.dismiss(id.value) id.value = '' } return ( <> <Button emphasis="outline" tone="neutral" disabled={!!id.value} onClick={start} > Start </Button> <Button emphasis="outline" tone="neutral" disabled={!id.value} onClick={stop} > Stop </Button> <Toaster /> </> )}On arrival
Fire one as a page mounts, to finish what the last page started.
tsx
import { onMount } from '@kerf-js/core'import { Text, Toaster, toast } from '@kerf-js/veneer'export function AfterRedirect() { onMount(() => toast.show({ title: 'Welcome back, Mara', description: 'You have two failed deploys to look at.', tone: 'info', }), ) return ( <> <Text subtle> This one fires as the page arrives. Press Replay. </Text> <Toaster /> </> )}When to use
Accessibility
- F8
- Moves focus to the newest toast
- Esc
- Leaves the toasts
- Toasts are read out through a live region that is on the page from the start.
- Hovering or focusing the stack pauses every timer.
- A critical toast with an action stays until it is dismissed.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
position | "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center… | — | The corner or edge toasts stack in, such as top-center. Bottom right otherwise. |
Parts
Every element carries a stable name, so you can style it from your own CSS: [data-scope="toast"] [data-part="region"]
regionrooticontitledescriptionactionsprogress