Components/Sonner

Sonner

A 52-tall card with three parts switched off. Nine variants cover every toast in the docs, because the interesting axes are hidden layers rather than properties.

Sonner · State, with the optional parts switched onLive in the browser · drawn to match the file
State
Icon
Description
Action
Title Text
336 × 52 in the fileradius.lg · 16 padding · gap 8base.border edge
Three parts, all hidden by default

The icon, the description and the action are layers sitting in the component with visibility off. Turning one on in an instance costs nothing and takes no variant, which is why State has only two values while the toast has eight useful shapes.

Fifty-two, or seventy-four

A title alone is 52 tall; a description under it makes 74. Nothing else changes the height - the icon is 20 inside 20 of padding and the action is 24, both shorter than the two lines of text they sit beside. Plan a stack on those two numbers.

Monochrome on purpose

All five status glyphs are base.foreground. No green tick, no red cross. That is sonner's default; colours arrive only with richColors, and the shape of the glyph is doing the work - a triangle warns whether or not it is yellow.

The status glyphs

Four filled shapes and a spinner

Twenty square, all in base.foreground. Four are Tabler's filled glyphs; the fifth is drawn by hand as twelve 2 by 5 bars around a circle, because a spinner has no single path and the file needed something that would still read as one when it is not moving.

Sonner / Icon · TypeLive in the browser · drawn to match the file
Type
Success toast
20 × 20base.foregroundone filled path
All of it at once

Fire some and watch them stack

This is the half a design file cannot hold: toasts arrive, pile up newest first, and leave on their own after four seconds. The loading one does not - it waits for the promise to settle, which is what toast.promise is for.

ToasterFour at a time, four seconds each
nothing to show - press a button above

Two things worth copying from the source. A loading toast has no timer, because dismissing it would leave the user thinking the work stopped. And the stack is capped - sonner shows three by default and collapses the rest - since a queue of nine toasts is a log file, not a notification.

The usage frame

Ten toasts, one component

1000 by 866, holding ten instances at 360 wide. Every one is the same component with a different set of layers switched on, which is the point of the frame: there is nothing to detach and nothing local in it.

Toast
Your changes have been saved
360 × 52 in the file

The wrapping title is the one worth looking at twice. At 360 wide with an icon beside it, the text column is 300, and a title long enough to wrap takes the toast from 52 to 72 without a description anywhere. If your stack assumes a fixed height, that is where it breaks.

Right to left

Three parts in one row, so all three swap ends

The toast is the widest row in the kit at three items: glyph, text, action. Under dir=rtl the glyph moves to the right edge and the action to the left, and the two text lines align to the right with them. The glyphs themselves are symmetrical enough not to need mirroring - a filled circle and a triangle read the same either way.

dir=rtlLive in the browser · drawn to match the file
Direction
Your changes have been savedTuesday, March 4th at 9:15am
Project moved to archive
Uploading three files
glyph on the left · action on the right

One thing worth checking in a real build: the toaster itself has a corner, and that corner is a position rather than a mirror. sonner defaults to bottom right, which in an RTL layout usually wants to become bottom left - the stack should arrive from the side the reader's eye returns to, and that is not something dir decides for you.

In the file

Three components, nine variants

Read straight out of the Penpot file. The axes below are the property names you will see in the variant dropdown.

Sonner / IconTypeSuccess · Info · Warning · Error · Loading - 20 × 20, all base.foreground5
SonnerStateDefault · Focus - 336 × 52, radius.lg on base.background2
Sonner / ActionTypeDefault · Secondary - 24 tall on radius.sm2

Using the Sonner

Because the three things that change are layers, not properties. The icon, the description and the action sit in the component with visibility off; switching one on in an instance costs nothing. Making them axes would have taken two variants to sixteen for a set of parts a designer toggles in the layer list anyway.

Fifty-two and seventy-four. A title alone is 52; a description under it makes 74. The icon is 20 and the action is 24, both shorter than the text column, so neither moves the height. The one that catches people is a title long enough to wrap - that takes a toast to 72 with no description in sight, and the usage frame has one on purpose.

Because that is sonner's default. Colour arrives with richColors and the kit does not assume it. Every glyph is base.foreground, and the shape carries the meaning - a filled triangle warns whether or not it is yellow, a filled circle with a cross reads as an error in black. If you turn richColors on, recolour the glyph in your instance.

By hand, as twelve 2 by 5 bars arranged around a circle with the opacity stepping up around the ring. A spinner is not a single path, and a static frame of one has to read as a spinner while standing still, which a plain arc does not. On this page it turns in twelve steps, which is what the bars are for.

Because dismissing it would tell the user the work stopped. Every other toast on this page clears itself after four seconds; the loading one waits to be replaced, which is what toast.promise does - one call, a loading toast while it runs and a success or error toast when it settles. The promise button on this page does exactly that.

Three in sonner's default, with the rest collapsed behind them. The demo here caps at four. Past that a toaster stops being a notification and becomes a log file, and the user reads none of them. If you need nine, you needed an inbox.

Feedback · 9 variants