Skip to content
weftGitHub

Toaster

Where toasts appear: short messages that come and go on their own.

SourcePackage @weft-js/warpPlayground

Preview

tsx
import { Button, Toaster, toast } from '@weft-js/warp'export function Basic() {  return (    <>      <Button onClick={() => toast.show({ title: 'Saved', description: 'Your changes are live.' })}>Save changes</Button>      <Toaster />    </>  )}

Installation

npm install @weft-js/warp

Usage

tsx
import { Toaster } from '@weft-js/warp'<>  <Button onClick={() => toast.show({ title: 'Saved', description: 'Your changes are live.' })}>Save changes</Button>  <Toaster /></>

Tones

Each tone brings its own icon.

tsx
import { Button, Toaster, toast } from '@weft-js/warp'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 const

Position

Use position on Toaster to pick the corner.

tsx
import { state } from '@weft-js/core'import { Button, Grid, Toaster, toast } from '@weft-js/warp'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 const

With an action

An action gives people ten seconds to take it.

tsx
import { state } from '@weft-js/core'import { Button, Toaster, toast } from '@weft-js/warp'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 '@weft-js/warp'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 '@weft-js/warp'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 '@weft-js/core'import { Button, Toaster, toast } from '@weft-js/warp'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 '@weft-js/core'import { Text, Toaster, toast } from '@weft-js/warp'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

Use it for

  • Confirming something people just did
  • News that doesn't need an answer

Reach for something else

  • Alert, when it has to stay on the page until it is dealt with
  • Modal, when people must answer before going on

Playground

Tone
import { Toaster } from '@weft-js/warp'toast.show({ title, description, tone, action })<Toaster />

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

PropTypeDefaultDescription
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

RelatedAlertProgressButton