sdxc

Type to search, or start from one of these:

Toast

A transient notification panel that floats above page content to report the outcome of an action, colored by one of five semantic tones and structured like an inline status panel.

View code
let toaster = new Toaster<Notice>({ defaultDuration: 6000 });
toaster.addEventListener("change", () => void handle.update());

<div mix={[hstack({ gap: 2, align: "center" })]}>
	<Button mix={[on<HTMLButtonElement, "click">("click", () => void toaster.add(notices.saved))]}>
		Publish
	</Button>
	<Button
		color="danger"
		variant="outline"
		mix={[on<HTMLButtonElement, "click">("click", () => void toaster.add(notices.failed))]}
	>
		Upload a bad file
	</Button>
	<Button
		variant="outline"
		mix={[on<HTMLButtonElement, "click">("click", () => void toaster.add(notices.invited))]}
	>
		Invite a teammate
	</Button>
</div>

<Toast.Region aria-label="Notifications" placement="bottom-end">
	{toaster.toasts.map((toast) => (
		<Toast
			key={toast.id}
			id={`preview-toast-${toast.id}`}
			color={toast.data.color}
			live={toast.data.color === "danger" ? "assertive" : "polite"}
			mix={[
				// The queue owns the countdown, so the mixin is here only to answer
				// the close button's --ui-dismiss command.
				dismiss({ duration: null }),
				on<HTMLDivElement, "ui:dismiss">("ui:dismiss", () => void toaster.dismiss(toast.id)),
				on<HTMLDivElement, "pointerenter">("pointerenter", () => toaster.pause(toast.id)),
				on<HTMLDivElement, "pointerleave">("pointerleave", () => toaster.resume(toast.id)),
			]}
		>
			<Toast.Icon>
				{toast.data.color === "success" ? (
					<CircleCheckIcon />
				) : toast.data.color === "danger" ? (
					<CircleAlertIcon />
				) : (
					<InfoIcon />
				)}
			</Toast.Icon>
			<Toast.Content>
				<Toast.Title>{toast.data.title}</Toast.Title>
				<Toast.Description>{toast.data.description}</Toast.Description>
			</Toast.Content>
			{toast.data.action ? <Toast.Action>{toast.data.action}</Toast.Action> : null}
			<Toast.Close
				aria-label="Dismiss"
				commandfor={`preview-toast-${toast.id}`}
				command="--ui-dismiss"
			/>
		</Toast>
	))}
</Toast.Region>

Installation

An ordinary dependency: install it, import the theme once, and import the component where it is used.

npm add @sdxc/ui
import "@sdxc/ui/theme.css";

Usage

import { Toast } from "@sdxc/ui";

Renders a single toast panel, tinted, bordered, and shadowed by Toast.Props.color, with role and aria-atomic defaulted (overridable); pair a mix-driven enterExit(), since it holds still.

Composition

The parts the component publishes, each a static property of the host.

  • Toast
  • Toast.IconRenders Toast.IconProps.children as the toast's leading icon, hidden from assistive technology since the toast's color and text already carry its meaning; swap in Toast.Loader while pending.
  • Toast.LoaderRenders Toast.LoaderProps.children as the toast's loading graphic, laid out identically to Toast.Icon so swapping between them keeps the layout stable; pair a spin() mix factory for its rotating loop.
  • Toast.ContentRenders Toast.ContentProps.children as the toast's body block: a column flex container that shrinks to fit alongside a leading icon or trailing action, holding Toast.Title and Toast.Description.
  • Toast.TitleRenders Toast.TitleProps.children as the toast's heading, in a native <h3> sized and weighted as a small, single-line label above the toast's description.
  • Toast.DescriptionRenders Toast.DescriptionProps.children as the toast's supporting message, in a native <p> set slightly translucent against the toast's foreground color so it reads as secondary to Toast.Title.
  • Toast.ActionRenders Toast.ActionProps.children as the toast's primary trailing control; type defaults to "button", ordered before the consumer's attributes so command/commandfor still run; use type="submit" for a form.
  • Toast.CancelRenders Toast.CancelProps.children as a neutral-tinted, secondary trailing control; type defaults to "button", ordered before the consumer's attributes so command/commandfor still run.
  • Toast.CloseRenders a dismiss control for the ancestor Toast: an icon-only <button> removable via a consumer's mixin or the commandfor/command pair; type="button" precedes those attributes so the pairing still runs.
  • Toast.RegionRenders the fixed viewport stacking every queued Toast at a corner via Toast.RegionProps.placement; pointer-events stays none so clicks pass through to content behind, restored per toast.

Examples

<Toast color="danger" live="assertive">
  <Toast.Content>
    <Toast.Title>{t("toasts.uploadFailed.title")}</Toast.Title>
  </Toast.Content>
  <Toast.Action>{t("actions.retry")}</Toast.Action>
  <Toast.Cancel>{t("actions.dismiss")}</Toast.Cancel>
</Toast>

Props

Read from the component's own types, so every prop, every default and every allowed value is listed.

PropTypeDescription
color?"brand" | "neutral" | "success" | "warning" | "danger"Semantic tone of the toast. Default: "neutral".
live?"polite" | "assertive" | "off"aria-live politeness for the toast's content. Default: "polite".
childrenRemixNodeThe toast's compound parts: Toast.Icon, Toast.Content, Toast.Action, or any other content.

Also accepts everything in TagProps<"div">.

Toast.Icon

PropTypeDescription
childrenRemixNodeThe icon graphic, typically a single SVG icon.

Also accepts everything in TagProps<"div">.

Toast.Loader

PropTypeDescription
childrenRemixNodeThe loading graphic shown in place of Toast.Icon while the toast represents pending work.

Also accepts everything in TagProps<"div">.

Toast.Content

PropTypeDescription
childrenRemixNodeThe toast's title, description, or other body content.

Also accepts everything in TagProps<"div">.

Toast.Title

PropTypeDescription
childrenRemixNodeThe toast's heading text.

Also accepts everything in TagProps<"h3">.

Toast.Description

PropTypeDescription
childrenRemixNodeThe toast's supporting message text.

Also accepts everything in TagProps<"p">.

Toast.Action

PropTypeDescription
childrenRemixNodeThe action's label.

Also accepts everything in TagProps<"button">.

Toast.Cancel

PropTypeDescription
childrenRemixNodeThe cancel control's label.

Also accepts everything in TagProps<"button">.

Toast.Close

PropTypeDescription
"aria-label"stringAccessible label for the icon-only control — required, since the button carries no visible text for assistive technology to read.

Also accepts everything in TagProps<"button">.

Toast.Region

PropTypeDescription
placement?"top-start" | "top-center" | "top-end" | "bottom-start" | "bottom-center" | "bottom-end"Corner of the viewport the stack renders in. Default: "bottom-end".
childrenRemixNodeEvery currently queued Toast.

Also accepts everything in TagProps<"div">.

Types

NameValuesWhat it decides
Color"brand" | "neutral" | "success" | "warning" | "danger"Semantic tone driving the host element's border, tint, and foreground color through the --ui-* variables for that color.
Live"polite" | "assertive" | "off"aria-live politeness applied to the host element.
Placement"top-start" | "top-center" | "top-end" | "bottom-start" | "bottom-center" | "bottom-end"Corner of the viewport Toast.Region renders in.