A toast variant with a trailing action button used for undo or in-flight confirmations.
action?: EBToastAction (label + callback) and supportingText?: String (the 10/15 BarkAda second line). Align width with base Toast (312 vs. 330 today) and swap the deprecated Button - Small/XS for Button - XSmall. Covers the "Undo / Retry / View" use cases and collapses two components into one.The actionable toast appears after reversible operations — "Transfer sent · Undo", "Message failed · Retry", "Photo uploaded · View". The action button sits right-aligned, tappable without dismissing the toast. Auto-dismiss is suppressed while an action is present.
Add label here
Add description here.
.[DEPRECATED] Button - Small/XS instance (scheduled for deletion). When that source is removed, this component breaks. Owns its surface tokens, but its action surface is borrowed from a deprecated source.type=default|light here vs. base Toast's type=default|pending|error and theme=default|light|dark — same axis name, incompatible value sets. Width is 330; base Toast is 312.| State | iOS | Android | Figma Property | Notes |
|---|---|---|---|---|
| Action tap | Yes | Yes | Button instance embedded | The deprecated Button - Small/XS is the action surface. Only one fixed appearance; consumers can't disable or show a loading spinner on the action. |
| Whole-container tap | N/A | N/A | Root is a <button> in some variants | The default, description=no variant wraps the whole toast in a button element, overlapping the inner action — tap target is unclear. |
| Auto-dismiss when action present | N/A | N/A | Not annotated | Toasts with actions should stay visible until the action is taken or explicitly dismissed. Not spec'd. |
| Action loading / disabled state | N/A | N/A | Not modeled | "Retry" actions often need a loading state after tap. No provision in the component. |
| A11y — action label | N/A | N/A | Text "Label" | The default text in the instance is literally "Label". Needs a content contract and an accessibility label override. |
- Separate component for a button slot that should be a prop on the base Toast. Material's Snackbar, SwiftUI's
.alert(actions:), and every other mature DS handle this as an optional action parameter — not a sibling record. Maintaining two components doubles the surface area of every future change and invites drift (different widths, different type sets). C1 · Layer Structure & Naming - Axis names + values drift from the base Toast. Base Toast exposes
type = default | pending | error+theme = default | light | dark. This sibling exposestype = default | light— same axis name, narrower value set, collides on meaning. Consumers wiring Code Connect can't treat them as the same prop. C2 · Variant & Property Naming -
description=yes|nois a slot + sizing flag bundled into a string. When description is present, vertical padding grows from 8 to 12 and a 4 px gap is inserted below the label. The trigger should be the presence of supporting-text content (supportingText?: String), not a hard-coded variant. C2 · Variant & Property Naming - Action surface uses the deprecated Button - Small/XS. The embedded Button instance (node
21:164490) is marked DEPRECATED in Figma, slated for deletion. When that source is removed, every variant of this toast breaks. Must re-link to Button - XSmall. C4 · Native Mappability - No icon axis at all. Base Toast has
With Icon = yes | no. This sibling drops the axis entirely — you can't have an actionable toast with a leading checkmark or error glyph. Merging into Toast recovers the icon automatically. C6 · Asset & Icon Quality - Whole-container tap overlaps the action button. The
default, description=novariant wraps the entire toast in a<button>element, while the inner action is also a button — two conflicting tap targets stacked. Behavior is undefined when the user taps the non-action area. C5 · Interaction State Coverage - Action has no states. No pressed, disabled, or loading state on the action. "Retry" actions commonly need a spinner after tap; destructive "Undo" often needs to grey out during processing. Not modeled. C5 · Interaction State Coverage
- Width 330 vs. base Toast 312. Inconsistent with the base Toast's fixed width. A single consolidated component picks one width (recommend 312, matching the rest of the family). C1 · Layer Structure & Naming
- Code Connect mappings not registered. Blocked on consolidation — there should be no separate Code Connect entry; the action slot maps to the base Toast's
actionparameter. C7 · Code Connect Linkability
- Consolidate into the base Toast. Remove Toast - With Button from the family. Base Toast picks up two new optional slots:
supportingText?: String(the 10/15 BarkAda second line) andaction?: EBToastAction(label + callback, with optional loading and disabled states). One component, covers every use case today and the ones this sibling misses (actionable error, actionable with icon). Family - Migrate the action surface to Button - XSmall. The embedded Button - Small/XS is marked deprecated in Figma. Rebind the action instance to the canonical Button - XSmall before the deprecated source is deleted — otherwise every variant breaks. Composition
- Replace
description=yes|nowith a supporting-text slot. Promote the second text line to an optional content slot. The padding and gap changes follow from the slot being populated — no duplicate variants required. Slot - Normalize width to 312. Match the base Toast. One width across the family. Property
- Define the action's state contract. Spec pressed / disabled / loading states on the action slot so "Retry" and "Undo" flows can reflect processing state. State
- Resolve the whole-container tap conflict. Decide: either the toast is dismiss-on-tap (drop the action as the only interactive surface), or the action owns the only tappable region. Pick one and drop the root
<button>wrapper from the other variants. State - Document auto-dismiss suppression when an action is present. A toast with an action stays visible until the user taps the action or explicitly dismisses. Call this out as a usage note. Docs
- Document the A11y announcement mapping. Action label feeds
accessibilityLabel(iOS) /contentDescription(Android). Live region polite for neutral, assertive if consolidated into a destructive Toast. A11y
Confirms a reversible action that the user might want to undo right away — "Removed from favorites", "Transfer sent". Pairs a label and optional description with a trailing action button.
Add label here
Add description here.
Default toast with a trailing action button. Theme axis flips surface + label between Dark and Light.
| Role | Token | Theme · Dark | Theme · Light |
|---|---|---|---|
| Surface bg | toast/color/{theme}/bg | #0A2757 | #FFFFFF |
| Border | toast/color/{theme}/border | #E5EBF4 | #E5EBF4 |
| Label | toast/color/{theme}/label | #FFFFFF | #0A2757 |
| Description | toast/color/{theme}/description | #F6F9FD @ 80% | #445C85 |
| Action label | toast/color/{theme}/action | #9BC5FD | #005CE5 |
This component collapses into the base Toast. Figma properties map to the consolidated Toast API, not to a standalone EBToastWithButton.
| Figma Property | SwiftUI | Compose |
|---|---|---|
Type: default | light | theme: light | dark (shared with Toast) | .ebToastTheme(.dark) |
Description: yes | no | supportingText?: String (slot) | supportingText: String? |
| (embedded Button - Small/XS — deprecated) | action?: ToastAction (slot) | action: EBToastAction? |
| (implicit label text) | message: String | message: String |
| (no icon axis) | leadingIcon?: Icon (inherited from Toast) | leadingIcon: Image? |
| Requirement | iOS | Android |
|---|---|---|
| Action label | Action passes accessibilityLabel through to the inner Button. Default: the visible label. | Action passes contentDescription to the inner Button. Default: the visible label. |
| Live region | Polite announcement; use the Toast's appearance to decide (destructive → assertive). | LiveRegionMode.Polite by default; assertive for destructive. |
| Suppress auto-dismiss | When action is non-nil, host overlay keeps the toast on screen until the action is tapped or the user swipes. | SnackbarDuration.Indefinite when an action is present. |
| Action loading state | Swap label for a ProgressView; keep the button reachable for VoiceOver (don't disable mid-announcement). | Swap label for a CircularProgressIndicator; set enabled = false after the state is announced. |
| Tap target | Action button must have a ≥ 44 × 44 hit area; the 24 px pill extends via .contentShape if visual size is smaller. | Action button must have a ≥ 48 dp touch target; use Modifier.minimumInteractiveComponentSize(). |
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Requires Rework | Separate component for a property slot. Consolidate into base Toast; normalize width from 330 to 312. |
| C2 | Variant & Property Naming | Requires Rework | type values drift from base Toast; description=yes|no should be a content slot. |
| C3 | Token Coverage | Ready | Surface, label, description, border tokens all bound via main/toast/color/{default|light}/*. Action uses comp/button-v1/default/*. |
| C4 | Native Mappability | Requires Rework | Action surface uses the deprecated Button - Small/XS; maps cleanly to Snackbar's action slot once migrated. |
| C5 | Interaction State Coverage | Requires Rework | No action states (pressed / disabled / loading); whole-container tap overlaps the inner action. |
| C6 | Asset & Icon Quality | Requires Rework | No leading-icon axis at all — consolidation recovers it from base Toast. |
| C7 | Code Connect Linkability | Not Mapped | Blocked on consolidation — no standalone Code Connect entry; action maps to base Toast's action parameter. |
Axes: Type (2) × Description (2) = 4 variants. Flat matrix — no collapsed axes, no illegal combinations. Every variant embeds the deprecated .[DEPRECATED] Button - Small/XS instance.
| # | Node | Type | Description | Dimensions | Notes |
|---|---|---|---|---|---|
| 1 | 813:31117 | default | yes | 330 × 74 | Root is a <button> element |
| 2 | 27:53213 | light | yes | 330 × 74 | Root is a <div> element |
| 3 | 813:31125 | default | no | 330 × 41 | Root is a <button> element (tap conflict) |
| 4 | 27:53225 | light | no | 330 × 41 | Root is a <div> element |
action?: EBToastAction. Width drifts from base (330 vs. 312). Opentype=default|light here vs. type=default|pending|error + theme=default|light|dark on base Toast. description=yes|no should be supportingText?: String. Open.[DEPRECATED] Button - Small/XS (node 21:164490), slated for deletion Aug 22, 2025. Rebind to Button - XSmall before migration. Opendescription=no variants wrap the root in a <button> overlapping the inner action. No pressed/disabled/loading states for the action. OpenWith Icon axis that base Toast exposes. Consolidation recovers it. Open