diff --git a/docs/app/components/ThemeProvider.tsx b/docs/app/components/ThemeProvider.tsx index 02ec6a9..9a9a120 100644 --- a/docs/app/components/ThemeProvider.tsx +++ b/docs/app/components/ThemeProvider.tsx @@ -4,7 +4,6 @@ import { createContext, useCallback, useContext, - useEffect, useState, type ReactNode, } from "react"; @@ -25,19 +24,21 @@ const ThemeContext = createContext({ const STORAGE_KEY = "tuikit-theme"; +/** + * Reads the theme that the blocking script already applied to the DOM. + * Falls back to "amber" if nothing is set yet (SSR or first visit). + */ +function getInitialTheme(): Theme { + if (typeof document !== "undefined") { + const attr = document.documentElement.getAttribute("data-theme") as Theme | null; + if (attr && themes.includes(attr)) return attr; + } + return "amber"; +} + /** Provides theme state and applies it to the document root via data-theme attribute. */ export function ThemeProvider({ children }: { children: ReactNode }) { - const [theme, setThemeState] = useState("amber"); - - useEffect(() => { - const stored = localStorage.getItem(STORAGE_KEY) as Theme | null; - if (stored && themes.includes(stored)) { - setThemeState(stored); - document.documentElement.setAttribute("data-theme", stored); - } else { - document.documentElement.setAttribute("data-theme", "amber"); - } - }, []); + const [theme, setThemeState] = useState(getInitialTheme); const setTheme = useCallback((next: Theme) => { setThemeState(next); diff --git a/docs/app/layout.tsx b/docs/app/layout.tsx index 27f3162..0e7430b 100644 --- a/docs/app/layout.tsx +++ b/docs/app/layout.tsx @@ -31,8 +31,27 @@ export default function RootLayout({ }: Readonly<{ children: React.ReactNode; }>) { + /** Inline script that runs before first paint to prevent theme flash (FOUC). */ + const themeInitScript = ` + (function() { + try { + var stored = localStorage.getItem('tuikit-theme'); + if (stored && ['green','amber','white','red'].includes(stored)) { + document.documentElement.setAttribute('data-theme', stored); + } else { + document.documentElement.setAttribute('data-theme', 'amber'); + } + } catch(e) { + document.documentElement.setAttribute('data-theme', 'amber'); + } + })(); + `; + return ( - + + +