Theme Picker
A gallery of themes to choose from, each previewed as it will look.
Live demo
Theme Picker is the choosing surface for a set of invocations. Every option is an <xtyle-theme-card>, so the preview, the button semantics, the accessible name, and the selected state all come from that component; the picker owns the grid, which card is current, and reporting the choice.
Turn on swatches and each card gets an <xtyle-theme-swatch> beneath it, pairing the picture with the parts list. It adds no cursor of its own — every card is already a real button, so focus moves through them the way it moves through any group of controls, and there is no bespoke roving tab stop to get wrong. Picking one fires xtyle:theme-pick carrying the whole invocation, not just a name, which is exactly what an <xtyle-theme-scope> needs to apply it: the two compose into a working theme switcher with no glue in between. With no themes it says so rather than rendering an empty grid.
When to use
How this component composes with the rest of the set.
Props
8 props, straight from the manifest.
| Prop | Type | Default | Bindings | Description |
|---|---|---|---|---|
Appearance
States
selected
The current choice, carried by the card's own selected state.
Anatomy
The named parts that make up the component, with their selectors.
grid
The gallery. A responsive auto-fill grid whose column floor is min-col-width.
item
One choice: its card, and its swatch row when swatches is on.
empty
Shown instead of the grid when there is nothing to choose from.
menu
The layout="menu" shell: an <xtyle-popover> holding the same gallery, with a trigger naming the current choice.
Tokens & coverage
What the component consumes, checked live against what the algorithm produces.
Live coverage check against the xtyle-default register
(derive(xtyleDefault, { anchors }) →
coverComponent(manifest, register)). Every token this component
consumes must be a key the algorithm produces.
--fg-2
--font-sans
--leading-tight
--space-2
--space-3
--text-xs
Accessibility
Code
A gallery wired to a scope
A set of invocations to choose from, with the pick handed straight to a theme scope.
<!-- A gallery of invocations to choose from -->
<xtyle-theme-picker
label="Theme"
value="Quiet"
themes='[
{"name":"Default","algorithm":"xtyle-default"},
{"name":"Quiet","algorithm":"xtyle-quiet"},
{"name":"Grape","constraints":{"--accent":"#7c5cff"}},
{"name":"Grape light","scheme":"light","constraints":{"--accent":"#7c5cff"}}
]'
></xtyle-theme-picker>
<!-- Picking one hands the whole invocation to a scope -->
<script type="module">
const picker = document.querySelector("xtyle-theme-picker");
const scope = document.querySelector("xtyle-theme-scope");
picker.addEventListener("xtyle:theme-pick", (event) => {
const { algorithm, scheme, constraints } = event.detail.theme;
if (algorithm) scope.setAttribute("algorithm", algorithm);
if (scheme) scope.setAttribute("scheme", scheme);
scope.setAttribute("constraints", JSON.stringify(constraints ?? {}));
});
</script>
<script lang="ts">
import { ThemePicker, ThemeScope } from "@xtyle/svelte";
const themes = [
{ name: "Default", algorithm: "xtyle-default" },
{ name: "Quiet", algorithm: "xtyle-quiet" },
{ name: "Grape", constraints: { "--accent": "#7c5cff" } },
];
let chosen = $state(themes[0]);
</script>
<ThemePicker {themes} label="Theme" value={chosen.name} onpick={(d) => (chosen = d.theme)} swatches />
<ThemeScope algorithm={chosen.algorithm} constraints={chosen.constraints}>
<p>Everything here wears the chosen theme.</p>
</ThemeScope>
---
import ThemePicker from "@xtyle/astro/ThemePicker.astro";
const themes = [
{ name: "Default", algorithm: "xtyle-default" },
{ name: "Quiet", algorithm: "xtyle-quiet" },
{ name: "Grape", constraints: { "--accent": "#7c5cff" } },
];
---
<ThemePicker {themes} label="Theme" value="Quiet" swatches minColWidth="14rem" />
<!-- the same picker as a toolbar dropdown -->
<ThemePicker {themes} label="Theme" value="Quiet" layout="menu" />