Get Started
Themer is a theme management library built for TanStack Start and TanStack Router. In most cases, you will use it to add light and dark mode support to your app.
This library uses the TanStack APIs, so it will not work with other frameworks. If you are using Next.js, next-themes is a good alternative. It also inspired this library.
Installation
Themer assumes you already have a TanStack app set up. To install it, run:
npm install @lonik/themer -s
Usage
ThemeProvider
Add ThemeProvider to your __root.tsx file and wrap the Outlet component:
import { ThemeProvider } from "@lonik/themer";
export const Route = createRootRoute({
component: () => (
<html lang="en" suppressHydrationWarning>
<head>
<HeadContent />
</head>
<body>
<ThemeProvider>
<Outlet />
</ThemeProvider>
<Scripts />
</body>
</html>
),
});
After that, ThemeProvider will apply the correct attributes to the root element (html in this case) so it can switch between themes.
Styling
By default, ThemeProvider adds a theme class to the root element. You can style elements based on that class. For example,
to change the page background for each theme, you can write:
:root.light {
background: white;
}
:root.dark {
background: black;
}
Toggle Theme
To toggle the theme, you can use the useTheme hook:
import { useTheme } from "@lonik/themer";
import { useHydrated } from "@tanstack/react-router";
import { Moon, Sun, SunMoon } from "lucide-react";
const themeOrder = ["system", "light", "dark"] as const;
type ThemeValue = (typeof themeOrder)[number];
export function Theme() {
const { theme, setTheme } = useTheme();
const currentTheme: ThemeValue = (theme as ThemeValue) ?? "system";
const hydrated = useHydrated();
const nextTheme = (value: ThemeValue): ThemeValue => {
const index = themeOrder.indexOf(value);
return themeOrder[(index + 1) % themeOrder.length]!;
};
const icon =
currentTheme === "light" ? (
<Sun size={16} />
) : currentTheme === "dark" ? (
<Moon size={16} />
) : (
<SunMoon size={16} />
);
return (
<button
suppressHydrationWarning
type="button"
aria-label={`Theme: ${currentTheme}. Click to switch theme`}
title={`Theme: ${currentTheme}`}
className="inline-flex h-8 w-8 items-center justify-center rounded-md border border-default-200 bg-default-50 text-default-500 hover:bg-default-100 cursor-pointer"
onClick={() => setTheme(nextTheme(currentTheme))}
>
{hydrated && icon}
</button>
);
}
That is all you need to get started. You can further customize the library with the props available on ThemeProvider.
