How the AI Website Cloner Template Handles Dark Mode Theming with Tailwind CSS v4 oklch Tokens

The template implements dark mode by storing oklch color values as CSS custom properties in src/app/globals.css, using Tailwind CSS v4's dark: variant to automatically switch themes based on the user's OS preference without JavaScript.

The JCodesMore/ai-website-cloner-template repository provides a token-driven theming system built on the perceptually uniform oklch color space. By defining design tokens in a global stylesheet and leveraging Tailwind CSS v4's built-in dark mode support, the template delivers automatic color scheme switching that applies consistently across all UI components.

CSS Custom Properties with oklch Tokens

The foundation of the dark mode system lies in src/app/globals.css, where all color values are declared as CSS custom properties using the oklch() color function. This approach separates design decisions from component markup, enabling a single source of truth for both light and dark themes.

Light Mode Definitions

The default color scheme is defined within the :root selector starting at line 52. These variables establish the baseline palette using oklch lightness, chroma, and hue values:

/* src/app/globals.css (lines 52-77) */
:root {
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.145 0 0);
  --border: oklch(0.922 0 0);
  --input: oklch(0.922 0 0);
  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);
}

Dark Mode Overrides

When the browser detects a dark color scheme preference, the values are overridden inside a @media (prefers-color-scheme: dark) block beginning at line 87:

/* src/app/globals.css (lines 87-117) */
@media (prefers-color-scheme: dark) {
  :root {
    --background: oklch(0.145 0 0);
    --foreground: oklch(0.985 0 0);
    --card: oklch(0.205 0 0);
    --card-foreground: oklch(0.985 0 0);
    --border: oklch(1 0 0 / 10%);
    --input: oklch(1 0 0 / 15%);
    --primary: oklch(0.922 0 0);
    --primary-foreground: oklch(0.205 0 0);
  }
}

Tailwind CSS v4 Configuration

The template uses Tailwind CSS version 4, which provides native support for the dark: variant without requiring manual configuration in tailwind.config.js. According to the dependencies listed in package.json at line 56, the project specifies "tailwindcss": "^4":

// package.json (line 56)
"tailwindcss": "^4"

Tailwind v4 processes these utilities through the PostCSS plugin registered in postcss.config.mjs. When the user's OS reports prefers-color-scheme: dark, Tailwind automatically applies the dark: prefixed utilities, which reference the overridden CSS variable values defined in the media query.

Component-Level Implementation

UI components consume these tokens through Tailwind utility classes that map to the CSS custom properties. The Button component in src/components/ui/button.tsx demonstrates this pattern between lines 9 and 21:

// src/components/ui/button.tsx (lines 9-21)
const buttonVariants = cva(
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
  {
    variants: {
      variant: {
        default:
          "bg-primary text-primary-foreground hover:bg-primary/90 dark:bg-input/30 dark:hover:bg-input/50",
        outline:
          "border-border bg-background hover:bg-muted hover:text-foreground dark:border-input",
      },
    },
  }
);

In this implementation, the dark: variants (such as dark:border-input and dark:bg-input/30) reference the CSS variables (--border, --input) that swap values based on the active color scheme.

Practical Usage Examples

Components automatically adapt to the user's preferred color scheme without additional logic. Here is how to use the dark-mode-aware button:

import { Button } from "@/components/ui/button";

export default function Example() {
  return (
    <Button className="bg-primary text-primary-foreground hover:bg-primary/90">
      Click me
    </Button>
  );
}

The bg-primary class resolves to the --primary CSS variable, which changes from oklch(0.205 0 0) in light mode to oklch(0.922 0 0) in dark mode.

For custom components, reference the design tokens directly to ensure consistency:

export function Card({ children }: { children: React.ReactNode }) {
  return (
    <div className="rounded-lg bg-card text-card-foreground p-4 shadow">
      {children}
    </div>
  );
}

Both bg-card and text-card-foreground pull from the token system, automatically rendering in the appropriate color space based on the prefers-color-scheme media query.

Summary

  • Token Architecture: Colors are defined as oklch() values in CSS custom properties within src/app/globals.css, providing a perceptually uniform color space that maintains contrast ratios across themes.
  • Automatic Switching: Dark mode activates through the @media (prefers-color-scheme: dark) media query at line 87, overriding the default :root values without JavaScript.
  • Tailwind v4 Integration: The template leverages Tailwind CSS v4's native dark: variant (confirmed by "tailwindcss": "^4" in package.json line 56) to conditionally apply styles based on the active color scheme.
  • Component Consistency: UI elements like the Button component in src/components/ui/button.tsx use utility classes that reference these variables, ensuring the entire interface updates cohesively when the OS theme changes.

Frequently Asked Questions

What are oklch color tokens?

oklch is a CSS color function representing the OKLab color space, which provides perceptual uniformity—meaning color changes appear consistent to the human eye regardless of hue. The template uses oklch(lightness chroma hue) syntax (e.g., oklch(1 0 0) for pure white) to define tokens that maintain accessibility contrast ratios better than HSL or RGB equivalents when switching between light and dark modes.

How does Tailwind CSS v4 handle dark mode differently?

Tailwind CSS v4 moves configuration into CSS files and provides the dark: variant automatically without requiring a darkMode setting in tailwind.config.js. As implemented in this template, the variant works immediately with the standard prefers-color-scheme media query, applying dark: prefixed utilities only when the user's OS is set to dark mode.

Where are the color tokens defined in this template?

All color tokens reside in src/app/globals.css. Light mode defaults appear starting at line 52 under the :root selector, while dark mode overrides begin at line 87 inside @media (prefers-color-scheme: dark). This centralizes theming logic and allows any component to reference semantic variables like --background, --foreground, or --card without hardcoding color values.

Can components override the global theme colors?

Yes. While components typically reference semantic tokens (e.g., bg-primary or text-muted-foreground), they can also use arbitrary values or explicit oklch colors for specific branding needs. However, the template encourages using the CSS variable system to maintain consistency with the automatic dark mode switching defined in globals.css.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →