Skip to content

Density Toggle

A copy-paste theme toggle component in pure HTML, CSS & vanilla JS. Zero dependencies, framework-agnostic, MIT-licensed.

Theme ToggleHTMLJavaScriptCSSany framework

Copy into your project

HTML
<!-- Density Toggle — Comfortable / Compact, rows re-space via transform -->
<button class="nuda-tt2-density" type="button" aria-pressed="true" aria-label="Toggle layout density">
  <span class="nuda-tt2-density__card" aria-hidden="true">
    <span class="nuda-tt2-density__row"></span>
    <span class="nuda-tt2-density__row"></span>
    <span class="nuda-tt2-density__row"></span>
    <span class="nuda-tt2-density__row"></span>
  </span>
  <span class="nuda-tt2-density__label">Compact</span>
</button>
JavaScript
/* Density Toggle — toggle aria-pressed and swap the visible label. */
(function () {
  var btn = document.querySelector('.nuda-tt2-density');
  if (!btn) return;
  var label = btn.querySelector('.nuda-tt2-density__label');
  btn.addEventListener('click', function () {
    var pressed = btn.getAttribute('aria-pressed') === 'true';
    btn.setAttribute('aria-pressed', String(!pressed));
    if (label) label.textContent = pressed ? 'Comfortable' : 'Compact';
    document.documentElement.dataset.density = pressed ? 'comfortable' : 'compact';
  });
})();
CSS
.nuda-tt2-density {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: 96px;
  padding: 10px;
  background: rgba(255,255,255,.04);
  border: 1px solid rgba(255,255,255,.08);
  border-radius: 10px;
  color: #cfcfcf;
  cursor: pointer;
}

.nuda-tt2-density:focus-visible {
  outline: 2px solid #e4ff54;
  outline-offset: 2px;
}

.nuda-tt2-density__card {
  position: relative;
  width: 100%;
  height: 56px;
}

.nuda-tt2-density__row {
  position: absolute;
  left: 0;
  width: 100%;
  height: 6px;
  border-radius: 2px;
  background: rgba(255,255,255,.14);
  transform: translateY(0);
  transition: transform .35s cubic-bezier(.4,0,.2,1),background .3s;
}

.nuda-tt2-density__row:nth-child(2) {
  transform: translateY(18px);
}

.nuda-tt2-density__row:nth-child(3) {
  transform: translateY(36px);
}

.nuda-tt2-density__row:nth-child(4) {
  transform: translateY(54px);
}

.nuda-tt2-density[aria-pressed="true"] .nuda-tt2-density__row:nth-child(1) {
  transform: translateY(0);
}

.nuda-tt2-density[aria-pressed="true"] .nuda-tt2-density__row:nth-child(2) {
  transform: translateY(11px);
}

.nuda-tt2-density[aria-pressed="true"] .nuda-tt2-density__row:nth-child(3) {
  transform: translateY(22px);
}

.nuda-tt2-density[aria-pressed="true"] .nuda-tt2-density__row:nth-child(4) {
  transform: translateY(33px);
}

.nuda-tt2-density[aria-pressed="true"] .nuda-tt2-density__row {
  background: rgba(228,255,84,.35);
}

.nuda-tt2-density__label {
  font: 600 10px ui-sans-serif,system-ui;
  color: #a1a1aa;
}

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

How to use Density Toggle

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 theme toggle components

← Browse all NudaUI components