87 lines
3.2 KiB
Plaintext
87 lines
3.2 KiB
Plaintext
---
|
|
title: Atomic composition
|
|
description: Build a custom appearance surface from controlled components without the preset dialog.
|
|
order: 1
|
|
toc:
|
|
- id: controlled-atoms
|
|
title: Controlled atoms
|
|
- id: compose-card
|
|
title: Compose a theme card
|
|
- id: connected-layer
|
|
title: State bindings
|
|
- id: live-preview
|
|
title: Live preview
|
|
---
|
|
|
|
## Controlled atoms {#controlled-atoms}
|
|
|
|
`ThemeModeField`, `ThemeModeOptionList`, `ColorVisionModeField`, `TextScaleField`, `TextScaleOptionList`, `MotionModeField`, `BrightnessField`, `ThemeColorPicker`, and `ThemeToggle` are driven by values and callbacks. They do not require preference context, so they can work with forms, preview tools, or another state library.
|
|
|
|
```tsx
|
|
<ThemeModeField value={mode} onValueChange={setMode} />
|
|
<ThemeModeOptionList value={mode} onValueChange={setMode} />
|
|
<ColorVisionModeField value={colorVisionMode} onValueChange={setColorVisionMode} />
|
|
<TextScaleField value={textScale} onValueChange={setTextScale} />
|
|
<MotionModeField value={motionMode} onValueChange={setMotionMode} />
|
|
<BrightnessField value={brightness} onValueChange={setBrightness} />
|
|
<TextScaleOptionList value={textScale} onValueChange={setTextScale} />
|
|
```
|
|
|
|
`AppearanceOptionList` is the reusable radio list behind `TextScaleOptionList`. Give its `items` a `value`, `label`, and optional `icon` and `description` to build theme, motion, color-vision, or brightness selectors with the same presentation. It uses native radio inputs for keyboard navigation and form semantics.
|
|
|
|
## Compose a theme card {#compose-card}
|
|
|
|
`ThemeConfigCard` combines base and accent color controls while keeping the configuration owned by the caller.
|
|
|
|
```tsx
|
|
<ThemeConfigCard
|
|
config={{ baseColor, accentColor }}
|
|
onConfigChange={setThemeColors}
|
|
scheme={resolvedTheme}
|
|
/>
|
|
```
|
|
|
|
For a more granular layout, compose `baseColorSwatches`, `accentColorSwatches`, and `ThemeColorSwatchButton` directly.
|
|
|
|
`ThemeColorPicker` uses the labeled `pill` style by default. For tighter layouts, switch to the color-only `swatch` style with its selected indicator:
|
|
|
|
```tsx
|
|
<ThemeColorPicker
|
|
title="Accent color"
|
|
swatches={accentColorSwatches}
|
|
value={accentColor}
|
|
variant="swatch"
|
|
onValueChange={setAccentColor}
|
|
/>
|
|
```
|
|
|
|
## State bindings {#connected-layer}
|
|
|
|
`AppearanceSettings` is the default binding layer between the atoms and the shared `PreferencesProvider`. A custom surface can use Appearance hooks such as `useThemeMode`, `useThemeConfig`, and `useResolvedTheme` without knowing shared-preference string keys or reusing the default layout.
|
|
|
|
```tsx
|
|
const [themeConfig, setThemeConfig] = useThemeConfig()
|
|
const resolvedTheme = useResolvedTheme()
|
|
|
|
<ThemeConfigCard
|
|
config={themeConfig}
|
|
onConfigChange={setThemeConfig}
|
|
scheme={resolvedTheme}
|
|
/>
|
|
```
|
|
|
|
## Live preview {#live-preview}
|
|
|
|
The documentation Sandbox can load a typed, multi-file example without embedding implementation details in MDX:
|
|
|
|
<Sandbox example="appearance/theme-colors" title="Theme color controls" />
|
|
|
|
For a single file, import the component and its raw source directly instead of creating a manifest:
|
|
|
|
```mdx
|
|
import Demo from "./Demo"
|
|
import source from "./Demo.tsx?raw"
|
|
|
|
<SingleFileSandbox component={Demo} filename="Demo.tsx" source={source} />
|
|
```
|