Warren UI

ThemeSelect

Applies a Warren theme via data-theme on <html> with optional localStorage persistence.

Theme

Signal Watch

TOKENS ONLY · ZERO COMPONENT EDITS
OK
Throughput
84.2%
Rejected
12
Latency
142ms
PICK A THEME — CANVAS, INK AND DOT GRID FOLLOW
Source
"use client"

import { Badge } from "@/registry/warren/badge/badge"
import { Panel } from "@/registry/warren/panel/panel"
import { Stat } from "@/registry/warren/stat/stat"
import { ThemeSelect } from "@/registry/warren/theme-select/theme-select"

export default function ThemeSelectDemo() {
  return (
    <div className="flex flex-wrap items-start gap-4">
      <div className="flex flex-col gap-1">
        <span className="font-mono text-[10px] uppercase tracking-wide text-muted-foreground">
          Theme
        </span>
        <ThemeSelect />
      </div>
      <Panel
        title="Signal Watch"
        subtitle="TOKENS ONLY · ZERO COMPONENT EDITS"
        actions={
          <Badge variant="success" dot>
            OK
          </Badge>
        }
        footer="PICK A THEME — CANVAS, INK AND DOT GRID FOLLOW"
      >
        <div className="flex divide-x divide-border">
          <Stat label="Throughput" value="84.2%" tone="primary" className="flex-1 pr-3" />
          <Stat label="Rejected" value="12" tone="danger" className="flex-1 px-3" />
          <Stat label="Latency" value="142ms" tone="teal" className="flex-1 pl-3" />
        </div>
      </Panel>
    </div>
  )
}

Installation

npx shadcn@latest add https://warren.eduard3v.com/r/theme-select.json

Usage

import { ThemeSelect } from "@/components/ui/theme-select"
<ThemeSelect />

How theming works

Selecting an option sets data-theme="<name>" on <html>. The five palettes — light, dark, jade, green-neon, dracula — ship inside @warren/warren-base as token-for-token override blocks, so every Warren component recolors without a single component edit (:root stays the canonical light palette; setting data-theme="light" explicitly is inert).

The choice persists as a plain string under the warren-theme localStorage key. To avoid a flash of light theme before React hydrates, restore it pre-paint with an inline script as early in <head> as possible (key must match DEFAULT_STORAGE_KEY):

<script>
  try {
    var t = localStorage.getItem("warren-theme")
    if (t) document.documentElement.setAttribute("data-theme", t)
  } catch (e) {}
</script>

Custom theme lists

Source
"use client"

import { ThemeSelect } from "@/registry/warren/theme-select/theme-select"

export default function ThemeSelectCustomThemes() {
  /* Isolated from the page theme: target={null} keeps this demo from fighting
     the site-chrome selects over documentElement — a mounted select otherwise
     applies its default on mount, clobbering the pre-paint-restored theme. */
  return (
    <ThemeSelect
      themes={[
        { value: "light", label: "PAPER" },
        { value: "dark", label: "NIGHT" },
      ]}
      storageKey={null}
      target={null}
    />
  )
}

Pass themes to offer any subset (or your own values backed by matching [data-theme] blocks), and storageKey={null} to disable persistence entirely. Pair storageKey={null} with target={null} for controls that must not drive the page theme: a mounted select otherwise applies its default to documentElement, which would clobber a theme restored by the pre-paint script above (multiple selects on one page fight over the attribute).

API Reference

Prop

Type

Prop

Type

On this page