NUI Provider
The NUIProvider is the root context wrapper for all NUI applications. It manages global theme state (light, dark, or system), synchronizes preferences with localStorage, listens for operating system theme changes, and exposes the useTheme hook.
import { NUIProvider, useTheme } from '@nofinite/nui';Overview
Unlike standard interactive UI widgets, NUIProvider is an application-level wrapper component. It injects and manages the .dark theme class on your root <html> or <body> element, ensuring that all NUI component styles automatically adapt between light and dark modes across your application.
All NUI components rely on NUIProvider being present at the root of your component tree.
Setup & Integration
Next.js App Router Setup
Place NUIProvider in your root layout (src/app/layout.tsx). We recommend adding suppressHydrationWarning to <html> to avoid React hydration mismatches when reading theme preference from localStorage:
import '@nofinite/nui/styles.css';
import { NUIProvider } from '@nofinite/nui';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<NUIProvider defaultTheme="system" storageKey="nui-theme">
{children}
</NUIProvider>
</body>
</html>
);
}Vite / React SPA Setup
In single-page React applications, wrap your root application tree in main.tsx or App.tsx:
import React from 'react';
import ReactDOM from 'react-dom/client';
import '@nofinite/nui/styles.css';
import { NUIProvider } from '@nofinite/nui';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<NUIProvider defaultTheme="system">
<App />
</NUIProvider>
</React.StrictMode>
);Switching Themes with useTheme
Use the useTheme() hook inside any child component to read the current theme, inspect the resolved DOM theme, or trigger theme changes:
import { useTheme, Button, Flex } from '@nofinite/nui';
export function ThemeSwitcher() {
const { theme, resolvedTheme, setTheme } = useTheme();
return (
<Flex align="center" justify="between" gap={16}>
<span>Current theme: <strong>{resolvedTheme}</strong></span>
<Flex gap={8}>
<Button
variant={theme === 'light' ? 'primary' : 'outline'}
size="sm"
onClick={() => setTheme('light')}
>
Light
</Button>
<Button
variant={theme === 'dark' ? 'primary' : 'outline'}
size="sm"
onClick={() => setTheme('dark')}
>
Dark
</Button>
<Button
variant={theme === 'system' ? 'primary' : 'outline'}
size="sm"
onClick={() => setTheme('system')}
>
System
</Button>
</Flex>
</Flex>
);
}API Reference
NUIProvider Props
| Prop | Type | Default | Description |
|---|---|---|---|
defaultTheme | enum | system | The default theme if nothing is in local storage. Defaults to 'system'. |
storageKey | string | nui-theme | The local storage key used to persist the theme preference. Defaults to 'nui-theme'. |
useTheme Hook Return Values
| Property | Type | Description |
|---|---|---|
theme | 'light' | 'dark' | 'system' | The user's active theme setting (including 'system'). |
resolvedTheme | 'light' | 'dark' | The actual computed theme active on the page ('light' or 'dark'). |
setTheme | (theme: ThemeMode) => void | Updates the active theme and persists the preference to localStorage. |
Best Practices
- Place at Root: Always mount
<NUIProvider>as close to the root of your application tree as possible. - Hydration Safety: When using Next.js or SSR frameworks, add
suppressHydrationWarningto the<html>tag to prevent client-server theme mismatch warnings. - Persistent Key: The
storageKeyprop defaults to'nui-theme'. If you run multiple apps on the same domain, configure unique storage keys to prevent theme conflicts.