Skip to content

Theme Selector

A copy-paste settings & preferences component in pure HTML & CSS. Zero dependencies, framework-agnostic, MIT-licensed.

Settings & PreferencesHTMLCSSany framework

Copy into your project

HTML
<div class="nuda-theme-sel" role="radiogroup" aria-label="Theme">
  <label class="nuda-theme-sel__swatch nuda-theme-sel__swatch--light">
    <input type="radio" name="theme" value="light" />
    <span class="nuda-theme-sel__chip"></span>
    <span class="nuda-theme-sel__name">Light</span>
  </label>
  <label class="nuda-theme-sel__swatch nuda-theme-sel__swatch--dark">
    <input type="radio" name="theme" value="dark" checked />
    <span class="nuda-theme-sel__chip"></span>
    <span class="nuda-theme-sel__name">Dark</span>
  </label>
  <label class="nuda-theme-sel__swatch nuda-theme-sel__swatch--system">
    <input type="radio" name="theme" value="system" />
    <span class="nuda-theme-sel__chip"></span>
    <span class="nuda-theme-sel__name">System</span>
  </label>
</div>
CSS
/* Theme Selector
   Three swatches in a row, one selected at a time.
   Customize: --selected, --swatch-bg */

.nuda-theme-sel {
  --selected: #e4ff54;
  --swatch-bg: #0c0c10;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.75rem;
  width: 100%;
  max-width: 420px;
}

.nuda-theme-sel__swatch {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem;
  background: var(--swatch-bg);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 12px;
  cursor: pointer;
  transition: border-color 0.2s ease, background 0.2s ease;
}

.nuda-theme-sel__swatch input {
  position: absolute;
  opacity: 0;
  inset: 0;
  cursor: pointer;
}

.nuda-theme-sel__chip {
  width: 100%;
  height: 48px;
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.08);
}

.nuda-theme-sel__swatch--light .nuda-theme-sel__chip {
  background: linear-gradient(135deg, #fafafa, #e4e4e8);
}

.nuda-theme-sel__swatch--dark .nuda-theme-sel__chip {
  background: linear-gradient(135deg, #1a1a1f, #09090b);
}

.nuda-theme-sel__swatch--system .nuda-theme-sel__chip {
  background: linear-gradient(135deg, #fafafa 0 50%, #1a1a1f 50% 100%);
}

.nuda-theme-sel__name {
  color: #a0a0a8;
  font-size: 0.75rem;
  font-weight: 500;
}

.nuda-theme-sel__swatch:has(input:checked) {
  border-color: var(--selected);
  background: #111114;
}

.nuda-theme-sel__swatch:has(input:checked) .nuda-theme-sel__name {
  color: #fafafa;
}

.nuda-theme-sel__swatch:has(input:focus-visible) {
  outline: 2px solid var(--selected);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .nuda-theme-sel__swatch {
    transition: none;
  }
}

How to use Theme Selector

Paste the HTML where you need it and the CSS into a global stylesheet (or a <style> tag). Every class is prefixed nuda- so it never collides with Tailwind or your own styles. Tweak the CSS custom properties to match your design system.

Works in React, Vue, Svelte, Astro, Next.js, Nuxt, Laravel Blade, Django, Rails — or a single .html file. No npm install, no build step.

More settings & preferences components

← Browse all NudaUI components