Toast: support internal consolidation — opt out of the forced MediaTheme surface and/or allow custom toast content
- Dominant language
- TypeScript
- Stars
- 13.1k
- Forks
- 1.1k
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 687
Description
## Summary
As we consolidate multiple internal component libraries onto Astryx, `Toast` is a friction point: other internal toast implementations look very different from Astryx's. The core blocker is that Astryx `Toast` **always renders its content inside a forced `MediaTheme`** (an inverted-surface theming context), and `ToastOptions` only exposes `body` / `endContent` / `type`. So a consumer consolidating onto Astryx can't (a) make the toast use their normal (non-media-inverted) surface styling, nor (b) inject the custom chrome their existing toast design needs. We want a sanctioned way to bridge the two.
## Current state (the coupling)
In `Toast.tsx`:
- `mediaMode = isError || mode === 'light' ? 'dark' : 'light'`, then the whole toast content is wrapped in `…`.
- `MediaTheme` sets `data-astryx-media="dark|light"`, applying inverted semantic-token overrides (colors/overlays/borders/`color-scheme`) to everything inside.
- The public surface (`ToastOptions`) is just `{ body, type?, autoHideDuration?, endContent? }` — no way to opt out of the media theme or supply fully custom structure.
Net effect: every Astryx toast renders on an inverted surface. Other internal toast designs don't look like that, and there's no escape hatch — so apps consolidating onto Astryx can't match their existing toast design.
## Two candidate directions (this issue is to design + pick)
**Option 1 — theme the toast to skip the media theme.**
Provide a way to render the toast *without* the forced `MediaTheme` wrap (or make the wrap themeable/opt-out), so toast content uses the app's normal surface tokens. Consider:
- A theme-level control (e.g. via `defineTheme` `components.toast`) or a Toast/provider prop that disables the media-inverted surface.
- What happens to the error variant (currently always dark) and the dismiss button's `color="inherit"` if the surface is no longer inverted.
- Whether this is per-toast or app-wide (a consolidating app likely wants app-wide "toasts use my surface, not the inverted one").
**Option 2 — allow custom elements in the toast provider.**
Expand the toast API so consumers can compose a toast matching their existing design:
- A richer render/slot escape hatch on `showToast` / the provider (beyond `body`+`endContent`) — e.g. a full custom render, or leading-icon/title/description slots — so the consumer owns the structure.
- If the consumer fully renders the toast, does the media theme still apply, or is Option 1 a prerequisite (custom content on a forced inverted surface is still wrong)?
These aren't mutually exclusive — Option 1 (surface/theming) may be the foundation and Option 2 (structure/slots) the ergonomics on top. The spec should decide the minimal surface that unblocks consolidation onto Astryx toasts.
## Constraints / considerations
- Reuse the theming system (`defineTheme` component overrides / MediaTheme opt-out) rather than bolting on toast-specific styling knobs — API/value reuse over a bespoke surface.
- Preserve a11y (`role=alert/status`, `aria-live`, dismiss button label) and auto-dismiss/pause-on-hover regardless of surface/structure.
- Non-breaking: the current media-inverted look stays the default; opting out / custom content is additive.
## Acceptance (post-design)
- A sanctioned way for an app consolidating onto Astryx to render toasts that match their existing design (either non-media-themed surface, custom structure, or both), decided via the spec.
- a11y + auto-dismiss behavior preserved; non-breaking default; spec reviewed before build.
Contributor guide
Research direction
Start by reading Toast.tsx, including the MediaTheme wrapper and ToastOptions, then trace showToast and the provider API. Review how defineTheme component overrides are used, compare the two proposed directions, and document a chosen minimal design that preserves accessibility, dismissal behavior, and the current default.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100