Documentation
Documentation
Introduction

Getting Started

Getting StartedInstallationQuick StartProject Structure

Architecture

Architecture OverviewTech StacktRPC MiddlewareDesign Principles

Patterns

Code Patterns & ConventionsFeature ModulesError HandlingType Safety

Database

DatabaseSchema DefinitionDatabase OperationsMigrationsCaching

API

tRPCProceduresRouterstRPC Proxy Setup
APIsOpenAPIREST Endpoints

Auth & Access

AuthenticationConfigurationOAuth ProvidersRolesSession Management
AuthorizationUser RolesPermissions

Routing & i18n

RoutingDeclarative RoutingNavigation
InternationalizationTranslationsLocale Routing

Components & UI

ComponentsButtonsFormsNavigationDialogs
StylesTailwind CSSThemingTypography

Storage

StorageConfigurationUsageBuckets

Configuration

ConfigurationEnvironment VariablesFeature Flags

Templates

Template GuidesCreate New FeatureCreate New PageCreate Database TableCreate tRPC RouterAdd Translations

Development

DevelopmentCommandsAI AgentsBest Practices

Theming

Light and dark mode theming

The project supports light and dark themes using CSS variables and the next-themes library.

Theme System

Themes are controlled via the ThemeProvider in src/providers/theme-provider.tsx:

import { ThemeProvider } from "@/providers/theme-provider";

<ThemeProvider
  attribute="class"
  defaultTheme="system"
  enableSystem
>
  {children}
</ThemeProvider>

Theme Configuration

Configure theme behavior in src/config/app.ts:

Config.Theme.DEFAULT = "system";        // "light" | "dark" | "system"
Config.Theme.ENABLE_SYSTEM = true;      // Allow system theme detection
Config.Theme.FORCE = undefined;         // Force specific theme (overrides user)

Options

SettingTypeDescription
DEFAULT"light" | "dark" | "system"Default theme
ENABLE_SYSTEMbooleanAllow system preference
FORCE"light" | "dark"Force theme (overrides user)

Using Themes

Theme Switcher

Import the theme switcher component:

import { ThemeSwitcher } from "@/components/theme-switcher";

<ThemeSwitcher />

This renders a dropdown with:

  • Light mode
  • Dark mode
  • System preference (if enabled)

Programmatic Control

Use the useTheme hook:

"use client";

import { useTheme } from "next-themes";

function MyComponent() {
  const { theme, setTheme, systemTheme } = useTheme();

  return (
    <div>
      <p>Current theme: {theme}</p>
      <button onClick={() => setTheme("light")}>Light</button>
      <button onClick={() => setTheme("dark")}>Dark</button>
      <button onClick={() => setTheme("system")}>System</button>
    </div>
  );
}

CSS Variables

Theme colors are defined using CSS variables in src/styles/globals.css:

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;
    --primary: 221.2 83.2% 53.3%;
    --primary-foreground: 210 40% 98%;
    /* ... more variables */
  }

  .dark {
    --background: 222.2 84% 4.9%;
    --foreground: 210 40% 98%;
    --primary: 217.2 91.2% 59.8%;
    --primary-foreground: 222.2 47.4% 11.2%;
    /* ... more variables */
  }
}

Variable Format

Variables use HSL format without the hsl() wrapper:

/* ✅ Correct */
--primary: 221.2 83.2% 53.3%;

/* ❌ Incorrect */
--primary: hsl(221.2, 83.2%, 53.3%);

Styling for Themes

Use the dark: prefix for dark mode styles:

<div className="bg-white dark:bg-gray-900">
  {/* White background in light mode, dark gray in dark mode */}
</div>

<p className="text-gray-900 dark:text-gray-100">
  {/* Dark text in light mode, light text in dark mode */}
</p>

Semantic Colors

Prefer semantic color tokens that adapt automatically:

// ✅ Good - automatically adapts to theme
<div className="bg-background text-foreground">
<div className="bg-primary text-primary-foreground">

// ❌ Avoid - requires manual dark: variants
<div className="bg-white dark:bg-black text-black dark:text-white">

Color Customization

Modifying Theme Colors

Edit src/styles/globals.css to customize colors:

:root {
  --primary: 221.2 83.2% 53.3%;  /* Light mode primary */
}

.dark {
  --primary: 217.2 91.2% 59.8%;  /* Dark mode primary */
}

Color Palette Generator

Use the Shadcn theme generator to create color palettes:

npx shadcn-ui@latest add

Or visit: https://ui.shadcn.com/themes

Theme-Aware Components

Components automatically adapt using CSS variables:

import { Card } from "@/components/ui/card";

<Card>
  {/* Automatically uses --card and --card-foreground */}
</Card>

Available Theme Variables

VariablePurpose
--backgroundPage background
--foregroundPrimary text
--cardCard background
--card-foregroundCard text
--primaryPrimary color
--secondarySecondary color
--mutedMuted background
--muted-foregroundMuted text
--accentAccent highlights
--destructiveDestructive actions
--borderBorders
--inputInput backgrounds
--ringFocus rings

Force Theme

To disable theme switching and force a specific theme:

// src/config/app.ts
Config.Theme.FORCE = "dark";  // Forces dark mode

This:

  • Hides the theme switcher
  • Ignores user preference
  • Overrides system preference

Best Practices

  1. Use semantic colors - Use bg-background, text-foreground instead of manual dark: variants
  2. Test both themes - Always test components in light and dark mode
  3. Avoid hardcoded colors - Use CSS variables for automatic theme adaptation
  4. Respect system preference - Enable system theme by default for better UX

The theme is stored in localStorage and persists across sessions.

On this page

Theme System
Theme Configuration
Options
Using Themes
Theme Switcher
Programmatic Control
CSS Variables
Variable Format
Styling for Themes
Semantic Colors
Color Customization
Modifying Theme Colors
Color Palette Generator
Theme-Aware Components
Available Theme Variables
Force Theme
Best Practices