AniUI

Theme Provider

Theme context provider with light, dark, and system mode support.

Installation#

npx @aniui/cli add theme-provider
LightDark
Light mode enabled
Web preview — components render natively on iOS & Android
import { ThemeProvider } from "@/components/ui/theme-provider";

export default function App() {
  return (
    <ThemeProvider defaultTheme="system">
      {/* Your app content */}
    </ThemeProvider>
  );
}

Usage#

app/_layout.tsx
import { ThemeProvider } from "@/components/ui/theme-provider";

export default function App() {
  return (
    <ThemeProvider defaultTheme="system">
      {/* Your app content */}
    </ThemeProvider>
  );
}

useTheme Hook#

Access the current theme, resolved theme, and theme controls from any child component.

Using useTheme
import { useTheme } from "@/components/ui/theme-provider";

export function ThemeToggle() {
  const { theme, resolvedTheme, setTheme, toggleTheme } = useTheme();

  return (
    <Button onPress={toggleTheme}>
      {resolvedTheme === "dark" ? "Switch to Light" : "Switch to Dark"}
    </Button>
  );
}
PropTypeDefault
theme
"light" | "dark" | "system"
-
resolvedTheme
"light" | "dark"
-
setTheme
(theme: Theme) => void
-
toggleTheme
() => void
-

Props#

PropTypeDefault
children
React.ReactNode
-
defaultTheme
"light" | "dark" | "system"
"system"
className
string
-

Accessibility#

  • ThemeProvider context for light/dark/system mode.
  • Respects the user's system-level accessibility preferences for color scheme.

Source#

components/ui/theme-provider.tsx
import React, { createContext, useCallback, useContext, useEffect, useState } from "react";
import { useColorScheme as useNativeColorScheme } from "react-native";
import { cn } from "@/lib/utils";
import { View } from "react-native";

type Theme = "light" | "dark" | "system";

const ThemeContext = createContext<{
  theme: Theme;
  resolvedTheme: "light" | "dark";
  setTheme: (theme: Theme) => void;
  toggleTheme: () => void;
}>({
  theme: "system",
  resolvedTheme: "light",
  setTheme: () => {},
  toggleTheme: () => {},
});

export function useTheme() {
  return useContext(ThemeContext);
}

export interface ThemeProviderProps {
  children: React.ReactNode;
  defaultTheme?: Theme;
  storageKey?: string;
  className?: string;
}

export function ThemeProvider({
  children,
  defaultTheme = "system",
  className,
}: ThemeProviderProps) {
  const systemScheme = useNativeColorScheme();
  const [theme, setThemeState] = useState<Theme>(defaultTheme);

  const resolvedTheme: "light" | "dark" =
    theme === "system" ? (systemScheme ?? "light") : theme;

  const setTheme = useCallback((newTheme: Theme) => {
    setThemeState(newTheme);
  }, []);

  const toggleTheme = useCallback(() => {
    setThemeState((prev) => {
      if (prev === "system") return systemScheme === "dark" ? "light" : "dark";
      return prev === "dark" ? "light" : "dark";
    });
  }, [systemScheme]);

  return (
    <ThemeContext.Provider value={{ theme, resolvedTheme, setTheme, toggleTheme }}>
      <View className={cn(resolvedTheme === "dark" ? "dark" : "", "flex-1 bg-background", className)}>
        {children}
      </View>
    </ThemeContext.Provider>
  );
}