Frameworks
Fumadocs
Setup guide for Fumadocs
Installation
npm install better-themesSetup
Update your root layout
In app/layout.tsx, wrap your app with ThemeProvider and disable Fumadocs' built-in theme:
import { RootProvider } from "fumadocs-ui/provider/next";
import { ThemeProvider } from "better-themes/rsc";
import type { ReactNode } from "react";
export default function Layout({ children }: { children: ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider attribute="class" disableTransitionOnChange>
<RootProvider theme={{ enabled: false }}>{children}</RootProvider>
</ThemeProvider>
</body>
</html>
);
}Important:
- Use the
/rscexport for Fumadocs (Next.js App Router) - Set
theme={{ enabled: false }}onRootProviderto disable Fumadocs' built-in theme system - Add
suppressHydrationWarningto your<html>tag
Create a theme switcher component
Create a client component for theme switching:
"use client";
import { useTheme } from "better-themes/rsc";
import { useEffect, useState } from "react";
export function ThemeSwitcher() {
const [mounted, setMounted] = useState(false);
const { theme, setTheme } = useTheme();
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return null;
}
return (
<button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
Toggle theme
</button>
);
}Add theme switcher to layouts
Add the theme switcher to both HomeLayout and DocsLayout:
Home Layout (app/(home)/layout.tsx):
import { HomeLayout } from "fumadocs-ui/layouts/home";
import { ThemeSwitcher } from "@/components/theme-switcher";
import type { ReactNode } from "react";
export default function Layout({ children }: { children: ReactNode }) {
return (
<HomeLayout themeSwitch={{ component: <ThemeSwitcher /> }}>
{children}
</HomeLayout>
);
}Docs Layout (app/docs/layout.tsx):
import { DocsLayout } from "fumadocs-ui/layouts/docs";
import { source } from "@/lib/source";
import { ThemeSwitcher } from "@/components/theme-switcher";
import type { ReactNode } from "react";
export default function Layout({ children }: { children: ReactNode }) {
return (
<DocsLayout
themeSwitch={{ component: <ThemeSwitcher /> }}
tree={source.pageTree}
>
{children}
</DocsLayout>
);
}Complete Example
import { RootProvider } from "fumadocs-ui/provider/next";
import { ThemeProvider } from "better-themes/rsc";
export default function Layout({ children }: LayoutProps<"/">) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider attribute="class" disableTransitionOnChange>
<RootProvider theme={{ enabled: false }}>{children}</RootProvider>
</ThemeProvider>
</body>
</html>
);
}import { HomeLayout } from "fumadocs-ui/layouts/home";
import { ThemeSwitcher } from "@/components/theme-switcher";
export default function Layout({ children }: LayoutProps<"/">) {
return (
<HomeLayout themeSwitch={{ component: <ThemeSwitcher /> }}>
{children}
</HomeLayout>
);
}import { DocsLayout } from "fumadocs-ui/layouts/docs";
import { source } from "@/lib/source";
import { ThemeSwitcher } from "@/components/theme-switcher";
export default function Layout({ children }: LayoutProps<"/docs">) {
return (
<DocsLayout
themeSwitch={{ component: <ThemeSwitcher /> }}
tree={source.pageTree}
>
{children}
</DocsLayout>
);
}"use client";
import { useTheme } from "better-themes/rsc";
import { useEffect, useState } from "react";
import { Monitor, Moon, Sun } from "lucide-react";
export function ThemeSwitcher() {
const [mounted, setMounted] = useState(false);
const { theme, setTheme } = useTheme();
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return null;
}
return (
<div>
<button onClick={() => setTheme("light")}>
<Sun />
</button>
<button onClick={() => setTheme("dark")}>
<Moon />
</button>
<button onClick={() => setTheme("system")}>
<Monitor />
</button>
</div>
);
}Notes
- Always use
better-themes/rscfor Fumadocs (Next.js App Router) - Disable Fumadocs' built-in theme by setting
theme={{ enabled: false }}onRootProvider - Remember to add
suppressHydrationWarningto the<html>tag - The theme switcher can be integrated into both
HomeLayoutandDocsLayoutusing thethemeSwitchprop
Example
View a complete example implementation: Fumadocs Example
Try the live demo: Live Demo