Theme Preset Provider

Applies the persisted theme preset on mount and injects a no-flash script so the saved preset is set before paint.

Report a bug

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Installation

pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/theme-preset-provider.json

Storybook

Explore all variants, controls, and accessibility checks in the interactive Storybook playground.

View in Storybook

Code

"use client"; import { type ReactNode, useEffect } from "react"; import { CUSTOM_THEME_NAME, DEFAULT_THEME_PRESET, isThemePresetName, THEME_CUSTOM_CSS_STORAGE_KEY, THEME_CUSTOM_STYLE_ID, THEME_PRESET_STORAGE_KEY, } from "../../lib/theme-presets"; import { setThemePreset } from "../../lib/use-theme-preset"; const FOUC_SCRIPT = `(function(){try{var v=localStorage.getItem(${JSON.stringify( THEME_PRESET_STORAGE_KEY, )});if(!v||v===${JSON.stringify( DEFAULT_THEME_PRESET, )})return;document.documentElement.setAttribute("data-theme",v);if(v===${JSON.stringify( CUSTOM_THEME_NAME, )}){var c=localStorage.getItem(${JSON.stringify( THEME_CUSTOM_CSS_STORAGE_KEY, )});if(c){var s=document.createElement("style");s.id=${JSON.stringify( THEME_CUSTOM_STYLE_ID, )};s.textContent=c;document.head.appendChild(s);}}}catch(e){}})();`; export type ThemePresetProviderProps = { readonly children?: ReactNode; /** Preset applied on first visit when no stored preference exists. */ readonly defaultPreset?: string; }; /** * Restores the persisted theme preset before paint (avoiding a flash) and * optionally seeds a default preset for first-time visitors. Render it once, * high in the tree, alongside the light/dark `ThemeProvider`. */ export function ThemePresetProvider({ children, defaultPreset, }: ThemePresetProviderProps) { useEffect(() => { if (!defaultPreset || defaultPreset === DEFAULT_THEME_PRESET) { return; } let stored: null | string = null; try { stored = window.localStorage.getItem(THEME_PRESET_STORAGE_KEY); } catch { stored = null; } if (!stored && isThemePresetName(defaultPreset)) { setThemePreset(defaultPreset); } }, [defaultPreset]); return ( <> <script dangerouslySetInnerHTML={{ __html: FOUC_SCRIPT }} suppressHydrationWarning /> {children} </> ); }

Dependencies

  • @vllnt/ui@^0.2.1