No-flash theme bootstrap script
interlace-ui/theme-scriptFreeUtility
@interlace/ui — the inline `<head>` script that applies the stored theme before first paint. Without it every page load flashes the default theme.
Install it
npx shadcn@latest add https://ds.interlace.tools/r/theme-script.jsonSource
1import { DEFAULT_THEME, THEMES } from '@/lib/theme-tokens';23// @interlace/theme-script v1.0.1 — Interlace design system.4// Docs, props and live preview: https://ds.interlace.tools/c/theme-script5// What changed since: https://ds.interlace.tools/c/theme-script#history6// Generated banner — keep it, the upgrade diff reads this version.78/**9 * @interlace/ui — the no-flash theme bootstrap.10 *11 * A theme applied after hydration is a WHITE FLASH on every page load: the12 * document paints `:root` (Interlace · light) first, React mounts, an effect13 * reads localStorage, and only then does the page repaint into the dark or14 * re-branded palette the user actually chose. On a fast connection that is15 * one frame of the wrong colours; on a slow one it is half a second of a16 * blinding white page. It is the single most visible failure mode of a theme17 * system, and no amount of correctness in the hook fixes it — by the time18 * any React code runs, the wrong paint has already happened.19 *20 * The only fix is to write the DOM attributes BEFORE first paint, which means21 * a synchronous, blocking, inline `<script>` in `<head>`. Hence a string22 * constant rather than a component: it has to be inlined by the host23 * document, and the host is the only thing that can put it there.24 *25 * ─── How consumers use it ─────────────────────────────────────────26 *27 * Next.js App Router (`app/layout.tsx`) — server component, no 'use client':28 *29 * ```tsx30 * import { THEME_SCRIPT } from '@interlace/ui/theme-script';31 *32 * <html lang="en" suppressHydrationWarning>33 * <head>34 * <script dangerouslySetInnerHTML={{ __html: THEME_SCRIPT }} />35 * </head>36 * ```37 *38 * `suppressHydrationWarning` on `<html>` is required and is the same thing39 * next-themes asks for: the script deliberately mutates the element React is40 * about to hydrate, so the server markup and the client DOM differ by41 * design. It suppresses the warning for that one element's attributes only.42 *43 * Vite / plain HTML: paste the string into `<head>` as an inline script, or44 * emit it at build time. It has no imports and no dependencies.45 *46 * ─── What it deliberately does NOT do ─────────────────────────────47 *48 * No feature detection beyond what it needs, no polyfills, no error49 * reporting. It is wrapped in one `try` and fails silently, because a50// … truncated
More from interlace-ui
All 140 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| cn — class-name merge utilitycn | interlace-ui | Utilities | Free | no deps | |
| Theme token manifesttheme-tokens | interlace-ui | Utilities | Free | no deps | |
| useReducedMotion hookuse-reduced-motion | interlace-ui | Utilities | Free | no deps | |
| useTheme hookuse-theme | interlace-ui | Utilities | Free | no deps |
