Preset picker
PresetPicker, PresetPickerSheet, PresetPickerContent, and related components.
The preset picker is a composable slide-out sheet UI that lets users search, preview, and select from all available presets. It is built from collaborating components that share state through a React context.
PresetPicker
Context provider that wires together the picker components. Wrap all picker sub-components inside it.
import {
PresetPicker,
PresetPickerSheet,
PresetPickerContent,
PresetPickerToggleButton,
PresetPickerThemeToggleGroup,
} from "@codecanon/next-presets";
<PresetPicker>
<PresetPickerToggleButton />
<PresetPickerSheet>
<PresetPickerThemeToggleGroup />
<PresetPickerContent />
</PresetPickerSheet>
</PresetPicker>Props
| Prop | Type | Description |
|---|---|---|
children | ReactNode | Required. Picker sub-components. |
usePresetPicker(caller?)
Hook to access the picker's open/close state from any component inside a <PresetPicker>. Useful for building custom triggers.
import { usePresetPicker } from "@codecanon/next-presets";
const { open, setOpen, toggleOpen } = usePresetPicker();Return values
| Property | Type | Description |
|---|---|---|
open | boolean | Whether the picker sheet is open. |
setOpen | (value: boolean) => void | Directly set open state. |
toggleOpen | () => void | Toggle open/closed. |
Throws an error if called outside of a <PresetPicker>.
PresetPickerSheet
Renders the slide-out sheet container. Animates in from the left. Non-modal — the rest of the app stays interactive while open.
<PresetPicker>
<PresetPickerSheet>
{/* content here */}
</PresetPickerSheet>
</PresetPicker>Extends the Sheet component props. The open and onOpenChange values are wired automatically from PresetPicker context. Pointer events outside the sheet do not close it.
PresetPickerContent
The main body of the picker — renders a search field and the full preset list with live previews.
<PresetPickerContent
showDock={false}
card={PresetPreviewCard}
presets={PRESETS}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
showDock | boolean | false | Render previews in a compact dock style. |
card | typeof PresetPreviewCard | PresetPreviewCard | Custom preview card component. Must accept the same props. |
presets | readonly PresetTuple[] | PRESETS | The list of presets to display. Spread to extend with custom entries. |
Extending with custom presets
Pass your own presets alongside the built-ins using the presets prop. Each entry is a [id, label] tuple — the id must match the data-preset value in your CSS:
import { PRESETS, PresetPickerContent } from "@codecanon/next-presets";
const MY_PRESETS = [
["my-brand", "My Brand"],
...PRESETS,
] as const;
<PresetPickerContent presets={MY_PRESETS} />Keyboard navigation
| Key | Action |
|---|---|
↑ / ↓ | Move through the preset list |
Enter | Apply the highlighted preset |
| Type | Filters the preset list by name |
PresetPickerThemeToggleGroup
Three-button toggle for switching between light, dark, and system modes. Place it inside <PresetPickerSheet> or anywhere else inside a <PresetPicker>.
import { PresetPickerThemeToggleGroup } from "@codecanon/next-presets";
<PresetPickerThemeToggleGroup />Accepts all React.ComponentProps<"div"> props. Internally calls useTheme() to read and set the current theme.
PresetPickerToggleButton
A ready-made button that opens and closes the preset picker sheet. Use it as a drop-in trigger without writing a custom usePresetPicker wrapper.
import {
PresetPicker,
PresetPickerSheet,
PresetPickerContent,
PresetPickerThemeToggleGroup,
PresetPickerToggleButton,
} from "@codecanon/next-presets";
<PresetPicker>
<PresetPickerToggleButton>🎨 Themes</PresetPickerToggleButton>
<PresetPickerSheet>
<PresetPickerThemeToggleGroup />
<PresetPickerContent />
</PresetPickerSheet>
</PresetPicker>Accepts all Button props including radix-ui asChild. The onClick handler is wired to toggleOpen automatically.
PresetPreviewCard
A mock app UI that renders in the colors of any preset — useful for previewing themes before applying them.
import { PresetPreviewCard } from "@codecanon/next-presets";
<PresetPreviewCard
preset="violet-bloom"
label="Violet Bloom"
active={false}
highlighted={false}
variant='default'
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
preset | string | — | Any preset ID (built-in or custom) whose colors to render. |
label | string | Auto-generated from preset | Display name shown on the card. |
active | boolean | false | Highlights the card with a primary-color ring (currently applied preset). |
highlighted | boolean | false | Highlights the card with a secondary ring (keyboard focus). |
variant | "default" | "dock" | "default" | Sidebar layout or compact dock layout |
ref | React.Ref<HTMLDivElement> | — | Forwarded to the root element. |
The card renders a miniature app chrome — sidebar, header, content cards, and footer — using the preset's CSS variables. This gives an accurate preview of how the preset will look in a real UI.
Custom preview card
Pass a custom component to PresetPickerContent via the card prop. It receives the same props as PresetPreviewCard:
import type { PresetPreviewCard } from "@codecanon/next-presets";
type PreviewCardProps = React.ComponentProps<typeof PresetPreviewCard>;
function MyPreviewCard({ preset, label, active }: PreviewCardProps) {
return (
<div data-preset={preset} style={{ border: active ? "2px solid blue" : "none" }}>
{label}
</div>
);
}
<PresetPickerContent card={MyPreviewCard} />You can also get the data from the usePreset hook.
import { usePreset, PRESET_BY_NAME, type PresetPreviewCard } from "@codecanon/next-presets";
type PreviewCardProps = React.ComponentProps<typeof PresetPreviewCard>;
function MyPreviewCard({ preset }: PreviewCardProps) {
const { preset: activePreset } = usePreset()
const active = preset === activePrest
const label = PRESET_BY_NAME[preset]
return (
<div data-preset={preset} style={{ border: active ? "2px solid blue" : "none" }}>
{label}
</div>
);
}
<PresetPickerContent card={MyPreviewCard} />Full example
import {
PresetPicker,
PresetPickerSheet,
PresetPickerContent,
PresetPickerThemeToggleGroup,
usePresetPicker,
} from "@codecanon/next-presets";
function TriggerButton() {
const { toggleOpen } = usePresetPicker();
return (
<button onClick={toggleOpen}>
🎨 Themes
</button>
);
}
export function ThemePicker() {
return (
<PresetPicker>
<TriggerButton />
<PresetPickerSheet>
<PresetPickerThemeToggleGroup />
<PresetPickerContent />
</PresetPickerSheet>
</PresetPicker>
);
}