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:

globals.css
@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:

app/layout.tsx
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>
  );
}

On this page