Getting started
Wrap your app with providers and add a theme preset picker.
1. Import the stylesheets
Add both imports at your app root — the preset file must come first:
@import "@codecanon/next-presets/default/nuteral.css";
@import "@codecanon/next-presets/styles.css";The first import sets the default :root variables (the appearance before any preset is chosen). The second loads all preset overrides. Swap nuteral.css for any other preset ID to change the default.
2. Wrap your app with providers
Add ThemeProvider and PresetProvider at the root. PresetProvider must be nested inside ThemeProvider:
import { ThemeProvider, PresetProvider } from "@codecanon/next-presets";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider>
<PresetProvider>
{children}
</PresetProvider>
</ThemeProvider>
</body>
</html>
);
}Both providers persist their state to localStorage and restore it on the next page load.
3. Add a preset picker
Use PresetPicker, PresetPickerSheet, and PresetPickerContent together to render a slide-out theme selector:
import {
PresetPicker,
PresetPickerSheet,
PresetPickerContent,
PresetPickerThemeToggleGroup,
} from "@codecanon/next-presets";
export function ThemeSidebar() {
return (
<PresetPicker>
<PresetPickerSheet>
<PresetPickerThemeToggleGroup />
<PresetPickerContent />
</PresetPickerSheet>
</PresetPicker>
);
}PresetPickerContent renders a searchable list of presets with live mini-app previews. It supports arrow-key navigation and Enter to select.
4. Open the picker programmatically
Use usePresetPicker to toggle the sheet from any button or trigger inside a <PresetPicker>:
import {
PresetPicker,
PresetPickerSheet,
PresetPickerContent,
PresetPickerToggleButton,
PresetPickerThemeToggleGroup,
usePresetPicker,
} from "@codecanon/next-presets";
function CustomOpenButton() {
const { toggleOpen } = usePresetPicker();
return <button onClick={toggleOpen}>Change Preset</button>;
}
export function App() {
return (
<PresetPicker>
<main className="my-app">
{/*Option A*/}
<PresetPickerToggleButton>Choose Preset</PresetPickerToggleButton>
{/*Option B*/}
<PresetPickerToggleButton asChild>
<button onClick={toggleOpen}>Change Preset</button>
</PresetPickerToggleButton>
{/*Option C: see above*/}
<CustomOpenButton />
</main>
<PresetPickerSheet>
<PresetPickerThemeToggleGroup />
<PresetPickerContent />
</PresetPickerSheet>
</PresetPicker>
);
}5. Read and set the preset in code
import { usePreset } from "@codecanon/next-presets";
function PresetControls() {
const { preset, setPreset, resetPreset } = usePreset();
return (
<div>
<p>Active: {preset ?? "none"}</p>
<button onClick={() => setPreset("violet-bloom")}>Violet Bloom</button>
<button onClick={() => setPreset("catppuccin")}>Catppuccin</button>
<button onClick={resetPreset}>Reset</button>
</div>
);
}6. Read and set the theme mode
import { useTheme } from "@codecanon/next-presets";
function ThemeToggle() {
const { isDarkTheme, setTheme } = useTheme();
return (
<button onClick={() => setTheme(isDarkTheme ? "light" : "dark")}>
{isDarkTheme ? "Switch to light" : "Switch to dark"}
</button>
);
}