#Better way to get theme?

4 messages · Page 1 of 1 (latest)

empty rover
#

Im accessing the theme cookie on __root during loader, but every client-side navigation triggers it.


export const Route = createRootRouteWithContext<RouterAppContext>()({
  component: RootComponent,
  loader: () => getThemeServerFn(),
});

function RootComponent() {
  const data = Route.useLoaderData();

  return <ThemeProvider theme={data}>{/*  */}</ThemeProvider>;
}

function RootDocument({children}: Readonly<{children: React.ReactNode}>) {
  const theme = Route.useLoaderData();

  return (
    <html lang="en" className={theme} suppressHydrationWarning>
      {/*  */}
    </html>
  );
}
import {createServerFn} from "@tanstack/react-start";
import {getCookie, setCookie} from "@tanstack/react-start/server";

type Theme = "dark" | "light";

const storageKey = "ui-theme";

export const getThemeServerFn = createServerFn().handler(async () => {
  return (getCookie(storageKey) || "light") as Theme;
});

export const setThemeServerFn = createServerFn({method: "POST"})
  .validator((data: unknown) => {
    if (typeof data != "string" || (data != "dark" && data != "light")) {
      throw new Error("Invalid theme provided");
    }
    return data as Theme;
  })
  .handler(async ({data}) => {
    setCookie(storageKey, data);
  });

Any better approach to just do it one time ?

daring gorge
#

Especially this:

hot verge
# empty rover Im accessing the theme cookie on `__root` during `loader`, but every client-side...

i use an inline script like this

https://github.com/dotnize/react-tanstarter/blob/2b19669206aa5a7b16a2520297c2051dc579f873/src/routes/__root.tsx#L66-L71
or with a custom theme provider: https://github.com/dotnize/react-tanstarter/blob/main/src/components/theme-provider.tsx#L94-L100

<ScriptOnce>
  {`document.documentElement.classList.toggle(
    'dark',
    localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)
    )`}
</ScriptOnce>

it's client-side and executes very early so there is no flash/FOUC