A transient bottom-anchored message for confirmations and inline alerts, with optional leading icon, description and trailing action. Auto-dismisses after a short delay.
4915:25141 in the 2026 Working File as Appearance × Theme × Size × three has* booleans, authored as a sparse 22-variant set. The family restructure is complete: Toast and Toast - With Button are merged, the overloaded theme axis is split, every variant value follows §5, layer naming is clean, and the description and trailing action are real Figma Slots composing shared components. All four DS Health traits pass. What remains is documentation — the dismiss and auto-duration contract, the native primitive mapping, and the a11y live-region behaviour.Toasts float over the app screen — not inline with content. Success toasts confirm completed actions ("Transfer sent"), pending toasts acknowledge background work ("Uploading…"), and error toasts surface failures that don't block the flow. They auto-dismiss after ~3 seconds unless swiped.
Add the popup message here
Subtext Message for the description and a Button - XSmall for the action, and each Appearance carries its own icon instance from the library. Nothing external required to render.Appearance and Theme are separate axes, Size uses the standard MD | SM scale, the three has* booleans carry correct verb prefixes and are genuine Figma booleans, and every variant value is Title Cased per §5.addon SLOT holding a Button - XSmall instance — addon being §4's canonical name for this pattern — and the description is a content SLOT carrying a shared Subtext Message. The separate Toast - With Button sibling is retired.| State | iOS | Android | Figma Property | Notes |
|---|---|---|---|---|
| Show / auto-dismiss | Yes | Yes | Not modeled | Toasts appear on a host overlay and auto-dismiss after a duration (~3s short, ~5s long). Host-screen concern — no visual state variant needed. |
| Swipe to dismiss | N/A | N/A | Not annotated | Standard gesture on both platforms. Not called out in the component spec. |
| Tap to dismiss | N/A | N/A | Not annotated | Pending variants already wrap the container in a button element in the Figma code — but no interaction callback is documented. |
| Pending spinner animation | N/A | N/A | Gray circle | Pending icon is a static gray circle (icon-placeholder) — should be an animated spinner (ProgressView / CircularProgressIndicator). |
| A11y announcement | N/A | N/A | Not annotated | Error toasts should announce as assertive; default/pending as polite. Not spec'd. |
- Code Connect mappings not registered. Blocked — no native library exists yet. C7 · Code Connect Linkability
- Toast and Toast - With Button consolidated. v2.0: Rebuilt on node
4915:25141in the 2026 Working File. The two components that modelled one primitive are now a single set — the trailing button is ahasTrailingActionboolean rather than a separate component. Confirmed as a permanent merge by the component owner. (C4 · Family) C4 · Native Mappability -
themeaxis split into Appearance and Theme. v2.0: The overloaded axis that mixed status with light/dark is nowAppearance(default · destructive · pending) ×Theme(dark · light), exactly as recommended. Semantic meaning and visual mode are independent. (C2 · Property) C2 · Variant & Property Naming -
Large Labelreplaced by a real Size axis. v2.0: The content flag masquerading as a size is nowSize = base | sm. Value naming still needs work — see open issues — but the axis itself is correct. (C2 · Rename) C2 · Variant & Property Naming - Boolean values normalised. v2.0:
hasLeadingIcon,hasTrailingActionandhasDescriptionusetrue/falserather thanyes/nostrings, and all three carry the correcthasverb prefix per §2. (C2 · Rename) C2 · Variant & Property Naming - Action slot added. v2.0: The trailing action is an
addonSLOTholding aButton - XSmallinstance — andaddonis the canonical name §4 gives for exactly this pattern. Consumers can swap the button without detaching. (Slot) C6 · Asset & Icon Quality - Description composed from the shared Subtext Message. v2.0: The description is a
contentSLOTcarrying a sharedSubtext Messageinstance, matching Text Area, Upload File and View Only Field. Copy changes propagate from one source. (Composition) C1 · Layer Structure & Naming - Size and Theme values aligned to the standard sets. v2.1:
Size = base | sm→MD | SM, matching §5'sXS · SM · MD · LG · XLscale and the values Amount Text Field and View Only Field use.Themeis nowDark | Lightin Title Case per §5. (C2 · Rename) C2 · Variant & Property Naming - Booleans confirmed as real Figma booleans. v2.1:
hasLeadingIcon,hasTrailingActionandhasDescriptionnow renderTrue/Falsecapitalised, matching every genuine Figma boolean elsewhere in the file. They map directly to SwiftBooland KotlinBoolean. (C2) C2 · Variant & Property Naming - Layer naming completed. v2.2:
container→ToastRow, the two siblingoffsetframes →LeadingIconandTextContent,text-container→TextGroup, and#content→Title. The two anonymous slots also gained names —Text-Slotfor the description andComponent-Slotfor the trailing action. (C1) C1 · Layer Structure & Naming - Pending placeholder replaced with a real icon. v2.2: The
icon-placeholderrectangle is gone.LeadingIconnow holds anInformationinstance from the icon library — chosen by the owner over a spinner, so Pending reads as an informational notice rather than an in-flight progress state. Each Appearance carries its own icon instance, which keeps glyph and semantic meaning in step and removes the need for a leading-icon slot. (C6 · Asset) C6 · Asset & Icon Quality - All variant values Title Cased. v2.3:
Appearance=pending→Pending, the last value the casing sweep had missed. Every one of the 22 variant names now conforms to §5 —Appearance = Default | Destructive | Pending,Theme = Dark | Light,Size = MD | SM, and threehas*booleans onTrue | False. (C2 · Rename) C2 · Variant & Property Naming - Dismiss and auto-duration contract documented. v2.4: Documented. Auto-hide — 4 seconds by default; 8 seconds when
hasTrailingAction=True, since the user needs time to read the message and reach the action.Appearance=Pendingdoes not auto-hide at all: it represents an in-flight operation and is replaced by a Default or Destructive toast when that operation resolves. Dismissal — a horizontal swipe in either direction dismisses. Tapping the toast body does nothing; only the trailing action is a tap target, and triggering it dismisses the toast. Stacking — one toast at a time; a new message replaces the current one rather than queueing behind it. Durations follow Material 3 Snackbar convention (4s short, longer when an action is present) rather than a product measurement, so they are a starting contract — say the word if product has specific numbers and I will amend. (C5 · Docs) C5 · Interaction State Coverage - Native mapping and a11y live region documented. v2.4: Documented. iOS — there is no system toast; build a custom view presented through a
ViewModifierover the root, anchored to the bottom safe area. Android — Material 3SnackbarwithSnackbarHostcovers the Default and Destructive appearances and mapshasTrailingActiononto its action slot, though the Pending appearance and the Theme axis need a custom composable. Accessibility — a transient message that is never focused must be announced, not merely rendered. On iOS post anAccessibilityNotification.Announcementwith the message text; on Android setModifier.semantics { liveRegion = LiveRegionMode.Polite }, raised toAssertiveforAppearance=Destructiveso an error interrupts rather than queues. The trailing action carries its own label; the leading icon is decorative and should be hidden from the accessibility tree. (C4 · A11y · Docs) C4 · Native Mappability
Confirms a completed action — transfer sent, settings saved, upload finished. Default theme places a checkmark glyph on a dark navy surface.
Add the popup message here
Information toast. Theme axis flips surface + label between Dark (navy) and Light (white).
| Role | Token | Theme · Dark | Theme · Light |
|---|---|---|---|
| Surface bg | main/toast/default/{theme}/bg | #0A2757 | #FFFFFF |
| Border | main/toast/default/{theme}/border | #E5EBF4 | #E5EBF4 |
| Label | main/toast/default/{theme}/label | #FFFFFF | #0A2757 |
| Icon | main/toast/default/{theme}/icon | #FFFFFF | #0A2757 |
Surfaces a failure that needs the user's attention — failed transfer, invalid input, expired session. Red surface with a leading X glyph.
Add the popup message here
Critical/error toast. Single appearance regardless of theme.
| Role | Token | Default |
|---|---|---|
| Surface bg | main/toast/error/bg | #D61B2C |
| Border | main/toast/error/border | #F4C7C9 |
| Label | main/toast/error/label | #FFFFFF |
| Icon | main/toast/error/icon | #FFFFFF |
Acknowledges in-flight work the user kicked off — submitting a form, syncing a balance, processing a payment. A spinner glyph signals the action is still running.
Add the popup message here
In-progress / loading state toast. Same surface palette as Default; spinner replaces the static icon.
| Role | Token | Theme · Dark | Theme · Light |
|---|---|---|---|
| Surface bg | main/toast/pending/{theme}/bg | #0A2757 | #FFFFFF |
| Border | main/toast/pending/{theme}/border | #E5EBF4 | #E5EBF4 |
| Label | main/toast/pending/{theme}/label | #FFFFFF | #0A2757 |
| Spinner | main/toast/pending/{theme}/spinner | #FFFFFF | #0A2757 |
The proposed schema collapses Toast + Toast - With Button into one API. Action becomes an optional slot, theme splits into appearance + theme, and Large Label becomes size.
| Figma Property | SwiftUI | Compose |
|---|---|---|
Type: default | pending | error | appearance: neutral | pending | destructive | appearance: EBToastAppearance |
Theme: default | light | dark (overloaded) | theme: light | dark (neutral + pending only) | .ebToastTheme(.dark) |
Large Label: yes | no | size: small | base | .controlSize(.small / .regular) |
With Icon: yes | no | leadingIcon?: Icon (slot) | leadingIcon: Image? |
| (implicit) | message: String | message: String |
| (separate component) | action?: ToastAction | action: EBToastAction? |
| (not modeled) | duration: short | long | duration: EBToastDuration |
| (not modeled) | onDismiss?: () -> Void | onDismiss: (() -> Void)? |
| Requirement | iOS | Android |
|---|---|---|
| Live region — error | Post UIAccessibility.Notification.announcement with .high priority on present. | Modifier.semantics { liveRegion = LiveRegionMode.Assertive } on the Snackbar container. |
| Live region — neutral / pending | Post announcement with default priority. | LiveRegionMode.Polite. |
| Minimum duration | Short ≥ 3s, long ≥ 5s; extend for longer messages per iOS HIG. | SnackbarDuration.Short / Long (Material 3 defaults). |
| Action button label | Action slot owns its own accessibilityLabel. | Action slot owns its own contentDescription. |
| Dismiss gesture | Swipe horizontally to dismiss; respect reduce-motion for the slide-out animation. | Swipe to dismiss built into Snackbar; honor TalkBackUserTouchExplorationEnabled to extend duration. |
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Requires Rework | Two components for one primitive — consolidate with Toast - With Button. |
| C2 | Variant & Property Naming | Requires Rework | theme overloaded with status; Large Label is a size flag; booleans on yes/no. |
| C3 | Token Coverage | Ready | All colors bound to main/toast/color/{mode}/*. Spacing + typography fully tokenized. |
| C4 | Native Mappability | Requires Rework | No SwiftUI first-party primitive; Compose has Snackbar. Needs documented mapping + ToastManager pattern. |
| C5 | Interaction State Coverage | Requires Rework | No auto-duration, swipe, or tap-to-dismiss contract; pending has no animation. |
| C6 | Asset & Icon Quality | Requires Rework | Pending uses icon-placeholder gray circle instead of a real spinner. |
| C7 | Code Connect Linkability | Not Mapped | Blocked on family consolidation and axis cleanup. |
Effective axes today: Type (3) × Theme (3, coupled to Type) × With Icon (2) × Large Label (2). Built variants collapse the illegal combinations — Error only pairs with theme=default; Pending only pairs with theme=dark | light + with icon=yes. = 16 built variants.
| Group | Count | Axes |
|---|---|---|
| Default / Dark | 4 | withIcon=yes/no × largeLabel=yes/no |
| Default / Light | 4 | withIcon=yes/no × largeLabel=yes/no |
| Error / Default | 4 | withIcon=yes/no × largeLabel=yes/no |
| Pending / Dark | 2 | withIcon=yes (forced) × largeLabel=yes/no |
| Pending / Light | 2 | withIcon=yes (forced) × largeLabel=yes/no |
theme axis, rename Large Label to size, and replace the Pending placeholder with a real spinner. Openaction slot. Opentheme mixes appearance + status; Large Label is a size flag; booleans on yes/no. Openicon-placeholder circle; adopt a real spinner instance. Open