Toaster
components/toaster.tsx: Sonner mounted once, styled on the palette, with Nyte icons and one dismiss label
import { Toaster } from "../components/toaster.tsx";
import { toast } from "@nyte-ai/ui/sonner";File: packages/desktop/src/renderer/src/components/toaster.tsx. Toaster mounts Sonner once in
the app root; everything else calls toast(...) from @nyte-ai/ui/sonner, which re-exports the
sonner package.
Configuration
| Setting | Value |
|---|---|
theme | From useAppearanceSettings(), so toasts follow the app theme. |
position | bottom-right, offset 16, gap 8, expand |
closeButton | on; closeButtonAriaLabel "Dismiss notification" |
containerAriaLabel | "Notifications" |
icons | success → checkmark, error and warning → warning, close → x |
toastOptions.unstyled | true; every class name is a StyleX class |
Action, cancel, and close buttons all carry focus.ring.
Usage rules
- Toasts are for outcomes the user did not just watch happen: a background failure, a folder that could not open, a copy confirmation. A form's own error stays in the form.
- Give a toast an
idwhen it can fire repeatedly, so a retry replaces it instead of stacking.open-workspace.tsxuses{ id: "workspace-open", duration: Infinity }for a failure that should stay until dismissed. - Titles are short and use
tabular-nums(counts line up). Descriptions wrap withtext-wrap: pretty.
toast.error("Couldn't open folder", {
id: "workspace-open",
duration: Infinity,
description: reason,
});
toast.success("Copied");Accessibility
Sonner renders a role="region" with the container label, and each toast as role="status" (or
alert for errors) so it is announced. The close button is a real button with a label.