MKSingh

Docs
TanstackStart

React Themes

Adding dark mode to your Tanstack-Start React App when using shadcn/ui.

This guide assumes that you have already initialized the shadcn/ui in your Tanstack Start react app. If not then you can initialize it by following the Installation Guide here.

Installation

To add dark mode to your Tanstack-Start React App, you need to simply run following command:

npx shadcn@latest add https://mksingh.dev/r/tanstack/start/react/themes.json

Usage

Once you have installed the theme configuration, now let's add the functions and components.

src/routes/__root.tsx
import { getThemeServerFn, ThemeProvider, useTheme } from '@/lib/theme'; 

export const Route = createRootRoute({
    head: () => ({
        meta: [
            {
                charSet: 'utf-8',
            },
            {
                name: 'viewport',
                content: 'width=device-width, initial-scale=1',
            },
            {
                title: 'TanStack Start Starter - MKSingh',
            },
        ],
        links: [
            {
                rel: "stylesheet",
                href: appCss,
            },
        ],
    }),
    component: RootComponent,
    beforeLoad: async () => await getThemeServerFn(), 
    loader: ({ context }) => context?.theme ? context : null, 
});

function RootComponent() {
    const themeValue = Route.useLoaderData(); 
    return (
        <ThemeProvider value={themeValue}>
            <RootDocument>
                <Outlet />
            </RootDocument>
        </ThemeProvider> 
    )
}

function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
    const { theme } = useTheme(); 
    return (
        <html className={theme} suppressHydrationWarning>
            <head>
                <HeadContent />
            </head>
            <body>
                {children}
                <Scripts />
                <Devtools />
            </body>
        </html>
    )
}

Theme switcher

How to implement the theme switcher?

useTheme hook provides -

  • theme which is the current theme and it can be light or dark only
  • definedBy can be system or user which is the source of the theme
  • setTheme function to change the theme. It accepts light or dark or system as an argument

Example

I've used kibo-ui as an example. It also works in same fashion like shadcn/ui. You can explore at kibo-ui However, you can use any other UI library as well.

Kibo-ui installation

You can install kibo-ui's components using shadcn/ui CLI or directly using kibo-ui CLI.

Shadcn/ui CLI

npx shadcn@latest add https://www.kibo-ui.com/registry/theme-switcher.json

Kibo-ui CLI

npx kibo-ui@latest add theme-switcher
src/components/theme-switcher.tsx
import { ThemeSwitcher } from '@/components/ui/kibo-ui/theme-switcher';
import { useTheme } from '@/lib/theme';

const ThemeSwitcherComponent = () => {
    const { theme, definedBy, setTheme } = useTheme();
    const value = definedBy === 'system' ? 'system' : theme; 

    return <ThemeSwitcher theme={value} onChange={setTheme} />
};