Theme Button
Provides an elegant and user-friendly way to cycle through light, dark, and system themes. It's specifically designed to work with next-themes, the most popular theme management library for Next.js applications.
npx shadcn@latest add https://shuip.plvo.dev/r/theme-button.json
pnpm dlx shadcn@latest add https://shuip.plvo.dev/r/theme-button.json
bun x shadcn@latest add https://shuip.plvo.dev/r/theme-button.json
import type { VariantProps } from 'class-variance-authority';import { Laptop, Moon, Sun } from 'lucide-react';import { useTheme } from 'next-themes';import * as React from 'react';import { Button, type buttonVariants } from '@/components/ui/button';type ButtonProps = React.ComponentProps<'button'> &VariantProps<typeof buttonVariants> & {asChild?: boolean;};type Theme = 'system' | 'light' | 'dark';export interface ThemeButtonProps extends ButtonProps {withText?: boolean;}export function ThemeButton({ withText, ...props }: ThemeButtonProps) {const { theme, setTheme } = useTheme();const [currentTheme, setCurrentTheme] = React.useState<Theme>('system');React.useEffect(() => {setCurrentTheme(theme as Theme);}, [theme]);const cycleTheme = () => {const themes: Theme[] = ['system', 'light', 'dark'];const currentIndex = themes.indexOf(currentTheme);const nextIndex = (currentIndex + 1) % themes.length;setTheme(themes[nextIndex]);};const getThemeIcon = () => {switch (currentTheme) {case 'system':return <Laptop className='size-[1.2rem]' />;case 'light':return <Sun className='size-[1.2rem]' />;case 'dark':return <Moon className='size-[1.2rem]' />;}};const getThemeText = () => {return currentTheme.charAt(0).toUpperCase() + currentTheme.slice(1);};return (<Button variant='outline' size={withText ? 'default' : 'icon'} onClick={cycleTheme} {...props}>{getThemeIcon()}{withText && <span className='ml-2 capitalize'>{getThemeText()}</span>}<span className='sr-only'>Toggle theme</span></Button>);}
Loading...
Ready-to-use theme toggle
The button automatically cycles through these states:
- System: Uses the user's OS preference (🖥️ Laptop icon)
- Light: Forces light mode (☀️ Sun icon)
- Dark: Forces dark mode (🌙 Moon icon)
With ThemeButton, a complete theme switcher in one line:
With ThemeButton - simple and complete
<ThemeButton />With text label
<ThemeButton withText={true} />Setup with next-themes
First, make sure you have next-themes installed and configured:
Examples
Default
Loading...
import { ThemeButton } from '@/components/ui/shuip/theme-button';export default function ThemeButtonExample() {return <ThemeButton />;}
Text
Loading...
import { ThemeButton } from '@/components/ui/shuip/theme-button';export default function ThemeButtonTextExample() {return <ThemeButton withText />;}
Props
Prop
Type