NUIv3.0.7

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.

tsx
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:

tsx
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:

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:

tsx
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

PropTypeDefaultDescription
defaultThemeenumsystemThe default theme if nothing is in local storage. Defaults to 'system'.
storageKeystringnui-themeThe local storage key used to persist the theme preference. Defaults to 'nui-theme'.

useTheme Hook Return Values

PropertyTypeDescription
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) => voidUpdates 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 suppressHydrationWarning to the <html> tag to prevent client-server theme mismatch warnings.
  • Persistent Key: The storageKey prop defaults to 'nui-theme'. If you run multiple apps on the same domain, configure unique storage keys to prevent theme conflicts.