Presets
All 50+ built-in color presets and how to use the preset system.
Each preset defines a complete set of CSS variables for both light and dark mode — covering background, foreground, primary, secondary, muted, accent, destructive, border, input, ring, sidebar colors, chart colors, and optional typography and shadow tokens.
How presets work
When a preset is active, PresetProvider sets data-preset="<id>" on document.documentElement. The library's CSS uses @variant preset-light and @variant preset-dark directives (from custom-variants.css) which expand into the full selector set:
/* Example: how violet-bloom is defined internally */
[data-preset="violet-bloom"] {
@variant preset-light {
--primary: #7033ff;
--background: #fdfdfd;
/* ... full light mode token set */
}
@variant preset-dark {
--primary: #8c5cff;
--background: #1a1b1e;
/* ... full dark mode token set */
}
}The preset-light variant applies variables when the element (or its ancestor) is in light mode — and also to any .scheme-light subtree. The preset-dark variant applies when in dark mode — and also to any .scheme-dark subtree. This means presets and dark/light mode are fully independent — every preset works in both modes.
scheme-light / scheme-dark
Scope light or dark mode to a specific subtree regardless of the global theme:
{/* Always renders in light mode, even when the app is dark */}
<div className="scheme-light">
<MyCard />
</div>
{/* Always renders in dark mode, even when the app is light */}
<div className="scheme-dark">
<MyCard />
</div>Using a preset
import { usePreset } from "@codecanon/next-presets";
const { setPreset } = usePreset();
setPreset("violet-bloom");Listing all presets
import { PRESETS } from "@codecanon/next-presets";
// Array of [id, label] tuples
PRESETS.forEach(([key, label]) => {
console.log(key, label);
});Available presets
| ID | Label |
|---|---|
nuteral | Nuteral |
nuteral-accent | Nuteral (Accent) |
codecanon | CodeCanon |
anew | Anew |
red | Red |
rose | Rose |
orange | Orange |
green | Green |
blue | Blue |
yellow | Yellow |
violet | Violet |
modern-minimal | Modern Minimal |
violet-bloom | Violet Bloom |
t3-chat | T3 Chat |
twitter | |
mocha-mousse | Mocha Mousse |
bubblegum | Bubblegum |
amethyst-haze | Amethyst Haze |
notebook | Notebook |
doom-64 | Doom 64 |
catppuccin | Catppuccin |
graphite | Graphite |
perpetuity | Perpetuity |
kodama-grove | Kodama Grove |
cosmic-night | Cosmic Night |
tangerine | Tangerine |
quantum-rose | Quantum Rose |
nature | Nature |
bold-tech | Bold Tech |
elegant-luxury | Elegant Luxury |
amber-minimal | Amber Minimal |
supabase | Supabase |
neo-brutalism | Neo Brutalism |
solar-dusk | Solar Dusk |
claymorphism | Claymorphism |
cyberpunk | Cyberpunk |
pastel-dreams | Pastel Dreams |
clean-slate | Clean Slate |
caffeine | Caffeine |
ocean-breeze | Ocean Breeze |
retro-arcade | Retro Arcade |
midnight-bloom | Midnight Bloom |
candyland | Candyland |
northern-lights | Northern Lights |
vintage-paper | Vintage Paper |
sunset-horizon | Sunset Horizon |
starry-night | Starry Night |
claude | Claude |
vercel | Vercel |
darkmatter | Darkmatter |
mono | Mono |
soft-pop | Soft Pop |
sage-garden | Sage Garden |
CSS tokens per preset
Each preset can define any of the following tokens. Typography and shadow tokens are optional — presets that omit them fall back to your app's base values.
| Token | Description |
|---|---|
--background / --foreground | Page background and text |
--card / --card-foreground | Card surface and text |
--popover / --popover-foreground | Popover surface and text |
--primary / --primary-foreground | Primary action color |
--secondary / --secondary-foreground | Secondary surface |
--muted / --muted-foreground | Subtle background and muted text |
--accent / --accent-foreground | Highlight / hover surface |
--destructive / --destructive-foreground | Destructive / error color |
--border / --input / --ring | Borders, inputs, focus rings |
--sidebar / --sidebar-foreground / … | Sidebar-specific tokens |
--chart-1 … --chart-5 | Data visualization palette |
--radius | Base border radius |
--font-sans / --font-serif / --font-mono | (optional) Preset-specific fonts |
--letter-spacing / --spacing | (optional) Typographic rhythm |
--shadow-color / --shadow-opacity / … | (optional) Shadow appearance |
Custom presets
Write your own preset CSS using the @variant preset-light and @variant preset-dark directives from custom-variants.css. Import this file in your CSS entry point alongside the library styles:
@import "@codecanon/next-presets/custom-variants.css";
:root, /* <-- add root if you want the preset to be default, otherwise remove */
[data-preset="my-brand"] {
@variant preset-light {
--background: oklch(0.99 0.005 220);
--foreground: oklch(0.1 0 0);
--primary: oklch(0.45 0.2 220);
--primary-foreground: oklch(0.98 0 0);
--secondary: oklch(0.93 0.02 220);
--secondary-foreground: oklch(0.2 0 0);
--muted: oklch(0.95 0.01 220);
--muted-foreground: oklch(0.5 0 0);
--accent: oklch(0.9 0.04 220);
--accent-foreground: oklch(0.15 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.88 0.01 220);
--input: oklch(0.88 0.01 220);
--ring: oklch(0.55 0.18 220);
--radius: 0.5rem;
/* sidebar, chart, font tokens... */
}
@variant preset-dark {
--background: oklch(0.1 0.005 220);
--foreground: oklch(0.97 0 0);
--primary: oklch(0.65 0.18 220);
/* ... dark mode values */
}
}@import "./my-brand-preset.css";
@import "@codecanon/next-presets/styles.css";Then register it in the picker and activate it:
import { PRESETS, PresetPickerContent } from "@codecanon/next-presets";
const MY_PRESETS = [["my-brand", "My Brand"], ...PRESETS] as const;
// In your picker:
<PresetPickerContent presets={MY_PRESETS} />
// Programmatically:
const { setPreset } = usePreset();
setPreset("my-brand");