Theme Preset Provider
Applies the persisted theme preset on mount and injects a no-flash script so the saved preset is set before paint.
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.jsonStorybook
Explore all variants, controls, and accessibility checks in the interactive Storybook playground.
View in StorybookCode
"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}
</>
);
}