[RFC] Make internally applied media theming configurable
- Dominant language
- TypeScript
- Stars
- 13k
- Forks
- 1.1k
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 690
Description
### Problem Statement
`XDSMediaTheme` is the right primitive for content rendered on inverted or image-backed surfaces, but the current model is difficult for themes to customize when components apply it internally.
Today, `XDSMediaTheme` works by setting `data-xds-media="dark|light"`. Generated theme CSS then applies default `onDark` / `onLight` token overrides and optional component overrides. This is useful for image overlays and high-contrast surfaces, but some component implementations apply media theming under the hood:
- Toast wraps its content/actions in `XDSMediaTheme`, choosing `dark` / `light` from the current mode and toast type.
- Overlay scrims wrap children in `XDSMediaTheme` when `scrim` is `dark` or `light`.
- Thumbnail wraps the remove button in `XDSMediaTheme` based on detected image luminance.
For themes, this creates two related problems:
1. If a component internally applies media theming, theme authors may need to customize both the normal component styles and the on-media component/token layer to get the intended result.
2. Some themes may want a specific component or surface to opt out of media token remapping entirely, but there is no clear API for disabling or overriding the internally applied media context.
This seems especially relevant for components like Toast, where the design may want branded/inverted/error surfaces that do not follow the default media-token remap.
## Current Behavior
- `defineTheme()` always resolves default `__onDark` and `__onLight` overrides through `resolveOnMedia()`.
- `generateOnMediaCSS()` emits `[data-xds-media="dark|light"]` token rules and component rules scoped under the active `data-xds-theme`.
- `XDSMediaTheme` itself only accepts `mode: 'dark' | 'light'`; there is no explicit inherit/disabled mode.
- Components that use `XDSMediaTheme` internally do not expose a consistent way to opt out of or override the media context.
## Rough Approaches to Consider
### 1. Component-level media control
Expose a small, component-specific escape hatch for components that apply media theming internally. For example, Toast could support a provider/default option or theme-level component setting equivalent to:
```ts
media: 'auto' | 'dark' | 'light' | 'none'
```
This keeps high-contrast defaults intact while allowing themes to opt out where the component owns the surface.
### 2. Theme-level media policy
Add a theme-level media policy that controls default on-media behavior globally or by component:
```ts
defineTheme({
media: {
defaults: true,
components: {
toast: false,
},
},
});
```
This would centralize policy, but needs careful design so it does not accidentally break contrast-sensitive usages like image overlays and thumbnails.
### 3. Expand `onDark` / `onLight` semantics
Allow `onDark` / `onLight` to explicitly disable default token remapping or reset specific tokens. This would be the smallest API surface, but it may be too global: disabling media defaults for all surfaces could harm accessibility in places where media theming is needed for contrast.
### 4. Add an inherit/disabled mode to `XDSMediaTheme`
Support an explicit inherit mode at the primitive level and let internal components forward a prop or theme option into it. This makes the primitive flexible, but the harder part is deciding which public component APIs should expose the control.
## Acceptance Criteria
- Audit all current internal `XDSMediaTheme` call sites and classify whether media theming is essential for contrast or a visual-design default.
- Decide whether opt-out should be component-level, theme-level, provider-level, or some combination.
- Preserve accessible contrast for image/dynamic-background cases by default.
- Make Toast theming easier without requiring duplicate normal + on-media overrides for common theme designs.
- Document how `onDark` / `onLight` interact with components that apply media theming internally.
## Notes
Relevant files:
- `packages/core/src/theme/XDSMediaTheme.tsx`
- `packages/core/src/theme/onMediaTokens.ts`
- `packages/core/src/theme/generateThemeRules.ts`
- `packages/core/src/Toast/XDSToast.tsx`
- `packages/core/src/Overlay/OverlayScrim.tsx`
- `packages/core/src/Thumbnail/XDSThumbnail.tsx`
Contributor guide
Assessment
This issue has not been assessed yet.