Remix
Setting up dark mode in your Remix project.
Update tailwind.css file.
This will allow you to use dark
class to apply dark mode styles.
tailwind.css
.dark,
:root[class~="dark"] {
/* Your dark mode styles */
}
Install remix-themes
.
npm install remix-themes
Create session storage.
sessions.server.tsx
import { createCookieSessionStorage } from "@remix-run/node"
import { createThemeSessionResolver } from "remix-themes"
const sessionStorage = createCookieSessionStorage({
cookie: {
name: "__remix-themes",
// domain: 'remix.run',
path: "/",
httpOnly: true,
sameSite: "lax",
secrets: ["s3cr3t"],
// secure: true,
},
})
export const themeSessionResolver = createThemeSessionResolver(sessionStorage)
Create action to set theme.
routes/action.set-theme.tsx
import { createThemeAction } from "remix-themes"
import { themeSessionResolver } from "../sessions.server"
export const action = createThemeAction(themeSessionResolver)
Add theme provider to root layout.
root.tsx
import "./tailwind.css"
import { LoaderFunctionArgs } from "@remix-run/node"
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
useLoaderData,
} from "@remix-run/react"
import clsx from "clsx"
import { PreventFlashOnWrongTheme, ThemeProvider, useTheme } from "remix-themes"
import { themeSessionResolver } from "./sessions.server"
export async function loader({ request }: LoaderFunctionArgs) {
const { getTheme } = await themeSessionResolver(request)
return {
theme: getTheme(),
}
}
export default function AppWithProviders() {
const data = useLoaderData<typeof loader>()
return (
<ThemeProvider specifiedTheme={data.theme} themeAction="/action/set-theme">
<App />
</ThemeProvider>
)
}
export function App() {
const data = useLoaderData<typeof loader>()
const [theme] = useTheme()
return (
<html lang="en" className={clsx(theme)}>
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<PreventFlashOnWrongTheme ssrTheme={Boolean(data.theme)} />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
)
}
Add theme toggle component.
components/theme-toggle.tsx
import * as React from "react"
import { MoonIcon, SunIcon } from "lucide-react"
import { Theme, useTheme } from "remix-themes"
import { Button } from "./ui/button"
export function ModeToggle() {
const [theme, setTheme] = useTheme()
const toggleTheme = React.useCallback(() => {
setTheme(theme === Theme.LIGHT ? Theme.DARK : Theme.LIGHT)
}, [theme, setTheme])
return (
<Button onClick={toggleTheme} variant="ghost" size="icon">
<MoonIcon className="dark:hidden" />
<SunIcon className="hidden dark:block" />
<span className="sr-only">Toggle theme</span>
</Button>
)
}