f-ui
Components

Theme Controls

Theme mode selector (light / dark / system) and compact light–dark toggle—presentational controls for nav and settings.

Theme appearance controls: a theme mode selector (three-way light / dark / system; ThemeModeSelector) and a theme mode toggle (compact light ↔ dark; ThemeModeToggle). Both use shadcn primitives and are controlled—they do not import next-themes; you connect value / onValueChange from useTheme() (or your own store). This site’s docs run inside Fumadocs RootProvider, which integrates with next-themes, so the demos below work without extra wiring.

Next Themes

Mount ThemeProvider from next-themes at your app root when you integrate outside Fumadocs. These components only render UI; they do not depend on next-themes at import time.

Theme Mode Selector

Light, dark, and system via a Select with sun / moon / monitor affordances.

Installation

Registry name theme-mode-selector. Same workflow as Installation.

pnpm dlx shadcn@latest add https://ui.isaacfei.com/r/theme-mode-selector.json
npx shadcn@latest add https://ui.isaacfei.com/r/theme-mode-selector.json
yarn dlx shadcn@latest add https://ui.isaacfei.com/r/theme-mode-selector.json
bun x shadcn@latest add https://ui.isaacfei.com/r/theme-mode-selector.json

Namespace: npx shadcn@latest add @f-ui/theme-mode-selector — pulls lucide-react and registry select.

Usage

import { ThemeModeSelector } from '@/components/f-ui/theme-mode-selector';
import { useTheme } from 'next-themes';

function NavTheme() {
  const { theme, setTheme } = useTheme();
  return (
    <ThemeModeSelector
      value={(theme as 'light' | 'dark' | 'system') ?? 'system'}
      onValueChange={setTheme}
      ariaLabel="Theme"
    />
  );
}

Translated labels:

<ThemeModeSelector
  value={theme}
  onValueChange={setTheme}
  options={[
    { value: 'light', label: '浅色' },
    { value: 'dark', label: '深色' },
    { value: 'system', label: '跟随系统' },
  ]}
/>

Composition

Select with Sun / Moon / Monitor on the trigger and one SelectItem per mode.

Example

Current:

"use client";

import { useTheme } from "next-themes";

import { ThemeModeSelector } from "@/components/f-ui/theme-mode-selector";

export function ThemeModeSelectorDemo() {
  const { theme, setTheme } = useTheme();
  const value =
    theme === "light" || theme === "dark" || theme === "system"
      ? theme
      : "system";

  return (
    <div className="max-w-sm space-y-3">
      <ThemeModeSelector
        value={value}
        onValueChange={setTheme}
        ariaLabel="Theme"
      />
      <p className="text-muted-foreground text-xs">
        Current:{" "}
        <span className="text-foreground font-medium tabular-nums">{theme ?? "—"}</span>
      </p>
    </div>
  );
}

API Reference

PropTypeDefault
value"light" | "dark" | "system"
onValueChange(value: ThemeMode) => void
optionsThemeModeOption[]Light / Dark / System
ariaLabelstring"Select theme"
classNamestring

Theme Mode Toggle

Compact control that flips between light and dark only (no system option on the control itself).

Installation

Registry name theme-mode-toggle.

pnpm dlx shadcn@latest add https://ui.isaacfei.com/r/theme-mode-toggle.json
npx shadcn@latest add https://ui.isaacfei.com/r/theme-mode-toggle.json
yarn dlx shadcn@latest add https://ui.isaacfei.com/r/theme-mode-toggle.json
bun x shadcn@latest add https://ui.isaacfei.com/r/theme-mode-toggle.json

Namespace: npx shadcn@latest add @f-ui/theme-mode-toggle — pulls lucide-react and registry button.

Usage

Use when you do not need a system option. Map next-themes “system” to a concrete value for display if needed.

import { ThemeModeToggle } from '@/components/f-ui/theme-mode-toggle';
import { useTheme } from 'next-themes';

function NavThemeToggle() {
  const { theme, setTheme } = useTheme();
  const resolved = theme === 'dark' ? 'dark' : 'light';

  return (
    <ThemeModeToggle
      value={resolved}
      onValueChange={setTheme}
      ariaLabel="Toggle theme"
    />
  );
}

Composition

Ghost Button with stacked sun/moon icons and CSS transitions for dark mode.

Example

Toggle drives light/dark; resolved for icon: light

"use client";

import { useTheme } from "next-themes";

import { ThemeModeToggle } from "@/components/f-ui/theme-mode-toggle";

export function ThemeModeToggleDemo() {
  const { theme, setTheme } = useTheme();
  const resolved = theme === "dark" ? "dark" : "light";

  return (
    <div className="flex max-w-sm flex-wrap items-center gap-4">
      <ThemeModeToggle
        value={resolved}
        onValueChange={setTheme}
        ariaLabel="Toggle theme"
      />
      <p className="text-muted-foreground text-xs">
        Toggle drives light/dark; resolved for icon:{" "}
        <span className="text-foreground font-medium tabular-nums">{resolved}</span>
      </p>
    </div>
  );
}

API Reference

PropTypeDefault
value"light" | "dark"
onValueChange(value: "light" | "dark") => void
ariaLabelstring"Toggle theme"
classNamestring

On this page