theme-provider.tsx
Overview
The theme-provider.tsx file implements a React context-based theming solution designed to manage and persist the UI theme state across a React application. It provides a ThemeProvider component that wraps application parts to supply theme-related state and functionality, including the current theme and a method to update it. The theming system supports persistent storage using localStorage, automatically applies the theme CSS class to the root document element, and offers several React hooks to consume and manipulate theme state easily.
This file is central to managing light/dark mode toggling in the UI, leveraging React's Context API and hooks for clean, reusable, and encapsulated theme logic.
Detailed Documentation
Types
ThemeProviderProps
type ThemeProviderProps = {
children: React.ReactNode;
defaultTheme?: ThemeEnum;
storageKey?: string;
};
children: React nodes to render inside the provider.
defaultTheme (optional): The default theme to fall back on if none is found in
localStorage. Defaults toThemeEnum.Light.storageKey (optional): The key string under which the theme is stored in
localStorage. Defaults to'vite-ui-theme'.
ThemeProviderState
type ThemeProviderState = {
theme: ThemeEnum;
setTheme: (theme: ThemeEnum) => void;
};
theme: The current theme (
ThemeEnum.LightorThemeEnum.Dark).setTheme: Function to update the theme.
Constants
initialState
const initialState: ThemeProviderState = {
theme: ThemeEnum.Light,
setTheme: () => null,
};
Provides the initial shape and default values for the theme context.
Sets default theme to
Light.setThemeis a no-op function initially.
Context
ThemeProviderContext
const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
React context to hold theme state and updater function.
Initialized with
initialState.
Component: ThemeProvider
function ThemeProvider({
children,
defaultTheme = ThemeEnum.Light,
storageKey = 'vite-ui-theme',
...props
}: ThemeProviderProps)
Purpose: Provides the theme context to its children and manages theme state.
Parameters:
children: React elements to render inside the provider.defaultTheme: Optional; default theme if no saved preference exists.storageKey: Optional; key forlocalStoragepersistence....props: Additional props passed to the underlying context provider.
Internal behavior:
Initializes state by reading from
localStorageusingstorageKey. If no stored theme exists, usesdefaultTheme.Uses
useEffectto:Remove any existing theme classes (
LightorDark) from the document root element.Add the current theme class to the root element. This enables CSS-based theming.
Persist the current theme to
localStorage.
Returns:
A
ThemeProviderContext.Providerwrappingchildren, providingthemeandsetThemein its value.
Usage example:
import { ThemeProvider } from './theme-provider';
import { ThemeEnum } from '@/constants/common';
function App() {
return (
<ThemeProvider defaultTheme={ThemeEnum.Dark}>
<MyAppComponents />
</ThemeProvider>
);
}
Hook: useTheme
export const useTheme = () => {
const context = useContext(ThemeProviderContext);
if (context === undefined)
throw new Error('useTheme must be used within a ThemeProvider');
return context;
};
Purpose: Custom hook to access the current theme and the setter function.
Usage: Must be called within a component wrapped by
ThemeProvider.Returns:
{ theme: ThemeEnum, setTheme: (theme: ThemeEnum) => void }Throws an error if used outside of a
ThemeProvider.
Hook: useIsDarkTheme
export const useIsDarkTheme = () => {
const { theme } = useTheme();
return theme === ThemeEnum.Dark;
};
Purpose: Convenience hook to check if the current theme is dark.
Returns:
trueif the theme is dark; otherwise,false.Usage example:
const isDark = useIsDarkTheme();
if (isDark) {
// Apply dark theme-specific logic
}
Hook: useSwitchToDarkThemeOnMount
export function useSwitchToDarkThemeOnMount() {
const { setTheme } = useTheme();
useEffect(() => {
setTheme(ThemeEnum.Dark);
}, [setTheme]);
}
Purpose: Hook to programmatically switch the theme to dark mode immediately upon component mount.
Usage example:
function ComponentThatForcesDarkTheme() {
useSwitchToDarkThemeOnMount();
return <div>Dark theme enforced</div>;
}
Important Implementation Details
Theme Persistence: The theme is stored in
localStorageunder a configurable key (storageKey). This ensures that the user's theme preference persists across browser sessions.DOM Manipulation: The theme CSS class is applied directly to the document root (
<html>) element, allowing global CSS rules to style the UI based on the active theme.Default Behavior: If no theme is saved, the
defaultThemeprop is used, defaulting to light mode.Strict Context Usage:
useThemeenforces usage within aThemeProviderto avoid undefined context usage, which improves developer experience and reduces bugs.Extensibility: The
ThemeEnumcan be extended with additional themes if needed, with minimal changes required in this file.
Interaction with Other Parts of the System
ThemeEnumimport: This enum (likely defined in@/constants/common) defines theme string constants such asLightandDark, ensuring consistency across the app.CSS Styling: The class added to
<html>(themevalue) must correspond to CSS selectors that apply theme-specific styles.Application Root: The
ThemeProvideris intended to wrap the root component or a large subtree of the React app to provide theme context globally.Other Components & Hooks: Components consume the theme state via
useThemeoruseIsDarkThemehooks to adjust rendering or styling accordingly.LocalStorage Dependency: Relies on browser
localStoragefor persistence; this file assumes a browser environment.
Visual Diagram
classDiagram
class ThemeProvider {
+children: ReactNode
+defaultTheme: ThemeEnum
+storageKey: string
+theme: ThemeEnum
+setTheme(theme: ThemeEnum): void
}
class ThemeProviderContext {
+theme: ThemeEnum
+setTheme(theme: ThemeEnum): void
}
class useTheme {
+(): ThemeProviderState
}
class useIsDarkTheme {
+(): boolean
}
class useSwitchToDarkThemeOnMount {
+(): void
}
ThemeProvider --> ThemeProviderContext : Provides context
useTheme ..> ThemeProviderContext : Uses context
useIsDarkTheme ..> useTheme : Uses hook
useSwitchToDarkThemeOnMount ..> useTheme : Uses hook
Summary
The theme-provider.tsx file establishes a robust, React idiomatic way to manage and persist UI themes with minimal setup. It leverages React Context and hooks to expose theme state and functionality, applies the theme CSS class globally to the document root, and persists user preferences in localStorage. The provided hooks simplify theme consumption and control across the app, supporting light and dark modes seamlessly. This file is a key part of the UI infrastructure enabling consistent theming throughout the application.