07 / 17
All 17 in 17 Tailwind CSS Range Sliders
- 01Tailwind CSS Dual-Handle Price Range Slider with Live Product Count
- 02Tailwind CSS Neumorphic Volume Slider with Soft UI Shadows
- 03Tailwind CSS Neon Glow Range Slider for Dark Mode UI
- 04Tailwind CSS Emoji Mood Slider for Feedback & CSAT Surveys
- 05Tailwind CSS Multi-Step Pricing Slider with Snapping Milestones
- 06Tailwind CSS Video Player Seekbar with Hover Scrub & Chapters
- 07Tailwind CSS Vertical Range Sliders — 10-Band Audio Equalizer
- 08Tailwind CSS Circular Dial Range Input — Smart Thermostat UI
- 09Tailwind CSS Gradient Range Slider with Progress Milestones
- 10Tailwind CSS Range Slider with Pop-Up Value Bubble (Loan Calculator)
- 11Tailwind CSS Brutalist Range Slider with Thick Block Track
- 12Tailwind CSS Password Strength Meter with Range Slider Control
- 13Tailwind CSS Centre-Origin Balance Slider for Audio Pan Control
- 14Tailwind CSS Retro 8-Bit Pixel Art Range Slider (Game HP Bar)
- 15Tailwind CSS Isometric 3D Range Slider with Perspective Plane
- 16Tailwind CSS Glassmorphism Range Sliders — RGBA Colour Mixer
- 17Tailwind CSS Liquid Glass Slider with Gooey Morphing Value Bubble
Tailwind CSS Vertical Range Sliders — 10-Band Audio Equalizer
Ten copper faders in inset steel grooves, dB readouts per band, four presets — and a live SVG response curve above the rack that the CSS original only listed as a "customization". Vertical orientation is one arbitrary utility pair now: [writing-mode:vertical-lr] [direction:rtl].
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="trs-07 w-full min-h-svh grid place-items-center bg-trs07-bg font-trs07-sans px-5 py-10">
<div class="w-[min(520px,100%)] rounded-3xl bg-trs07-panel border border-trs07-edge p-8 shadow-[0_24px_70px_-26px_oklch(0_0_0/0.85)]">
<header class="flex items-center justify-between gap-4 mb-6">
<h3 class="text-sm font-bold uppercase tracking-[0.2em] text-trs07-ink m-0">Equalizer</h3>
<div class="flex gap-1.5" aria-hidden="true">
<span class="size-2 rounded-full bg-[#ff5f57] shadow-[0_0_6px_#ff5f57]"></span>
<span class="size-2 rounded-full bg-[#febc2e] shadow-[0_0_6px_#febc2e]"></span>
<span class="size-2 rounded-full bg-[#28c840] shadow-[0_0_6px_#28c840]"></span>
</div>
</header>
<svg viewBox="0 0 300 60" class="w-full h-14 mb-2 overflow-visible" aria-hidden="true">
<defs>
<linearGradient id="trs-07-curve" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="var(--color-trs07-copper)"/>
<stop offset="100%" stop-color="var(--color-trs07-copperlit)"/>
</linearGradient>
</defs>
<line x1="0" y1="30" x2="300" y2="30" class="stroke-trs07-edge" stroke-width="1" stroke-dasharray="3 4"/>
<polyline id="trs-07-curve-line" fill="none" stroke="url(#trs-07-curve)" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round" points=""/>
</svg>
<div class="flex justify-between items-end h-52 mb-4" id="trs-07-rack" role="group" aria-label="Frequency bands"></div>
<div class="flex flex-wrap gap-2 pt-4 border-t border-trs07-edge" id="trs-07-presets" role="group" aria-label="Equalizer presets">
<button type="button" data-preset="flat" aria-pressed="true" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Flat</button>
<button type="button" data-preset="bass" aria-pressed="false" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Bass boost</button>
<button type="button" data-preset="treble" aria-pressed="false" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Treble</button>
<button type="button" data-preset="vocal" aria-pressed="false" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Vocal</button>
</div>
</div>
</section><section class="trs-07 w-full min-h-svh grid place-items-center bg-trs07-bg font-trs07-sans px-5 py-10">
<div class="w-[min(520px,100%)] rounded-3xl bg-trs07-panel border border-trs07-edge p-8 shadow-[0_24px_70px_-26px_oklch(0_0_0/0.85)]">
<header class="flex items-center justify-between gap-4 mb-6">
<h3 class="text-sm font-bold uppercase tracking-[0.2em] text-trs07-ink m-0">Equalizer</h3>
<div class="flex gap-1.5" aria-hidden="true">
<span class="size-2 rounded-full bg-[#ff5f57] shadow-[0_0_6px_#ff5f57]"></span>
<span class="size-2 rounded-full bg-[#febc2e] shadow-[0_0_6px_#febc2e]"></span>
<span class="size-2 rounded-full bg-[#28c840] shadow-[0_0_6px_#28c840]"></span>
</div>
</header>
<svg viewBox="0 0 300 60" class="w-full h-14 mb-2 overflow-visible" aria-hidden="true">
<defs>
<linearGradient id="trs-07-curve" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="var(--color-trs07-copper)"/>
<stop offset="100%" stop-color="var(--color-trs07-copperlit)"/>
</linearGradient>
</defs>
<line x1="0" y1="30" x2="300" y2="30" class="stroke-trs07-edge" stroke-width="1" stroke-dasharray="3 4"/>
<polyline id="trs-07-curve-line" fill="none" stroke="url(#trs-07-curve)" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round" points=""/>
</svg>
<div class="flex justify-between items-end h-52 mb-4" id="trs-07-rack" role="group" aria-label="Frequency bands"></div>
<div class="flex flex-wrap gap-2 pt-4 border-t border-trs07-edge" id="trs-07-presets" role="group" aria-label="Equalizer presets">
<button type="button" data-preset="flat" aria-pressed="true" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Flat</button>
<button type="button" data-preset="bass" aria-pressed="false" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Bass boost</button>
<button type="button" data-preset="treble" aria-pressed="false" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Treble</button>
<button type="button" data-preset="vocal" aria-pressed="false" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Vocal</button>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-trs07-bg: #111318;
--color-trs07-bg: oklch(0.18 0.01 262);
--color-trs07-panel: #1a1d24;
--color-trs07-panel: oklch(0.23 0.012 262);
--color-trs07-edge: #2d3240;
--color-trs07-edge: oklch(0.32 0.018 262);
--color-trs07-copper: #b87333;
--color-trs07-copper: oklch(0.62 0.12 55);
--color-trs07-copperlit: #d4925a;
--color-trs07-copperlit: oklch(0.72 0.1 55);
--color-trs07-ink: #e2e8f0;
--color-trs07-ink: oklch(0.92 0.01 255);
--color-trs07-mut: #8a97ab;
--color-trs07-mut: oklch(0.66 0.025 255);
--font-trs07-sans: 'Space Grotesk', system-ui, sans-serif;
--font-trs07-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.trs-07 {
width: 100%;
min-height: 100svh;
}
/* Faders: the copper cap, plus the vertical appearance fallback for older
WebKit. Everything else about orientation is a utility. */
.trs-07 input[type="range"] {
-webkit-appearance: slider-vertical;
}
.trs-07 input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 30px;
height: 18px;
border-radius: 4px;
background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
border: 1px solid oklch(1 0 0 / 0.16);
box-shadow: 0 2px 8px oklch(0 0 0 / 0.5), inset 0 1px 0 oklch(1 0 0 / 0.2);
cursor: grab;
transition: box-shadow .15s;
}
.trs-07 input[type="range"]:active::-webkit-slider-thumb {
cursor: grabbing;
box-shadow: 0 0 0 4px color-mix(in oklab, var(--color-trs07-copper) 32%, transparent), 0 2px 8px oklch(0 0 0 / 0.5);
}
.trs-07 input[type="range"]::-moz-range-thumb {
width: 30px;
height: 18px;
border-radius: 4px;
background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
border: 1px solid oklch(1 0 0 / 0.16);
cursor: grab;
}
@media (prefers-reduced-motion: reduce) {
.trs-07 input[type="range"]::-webkit-slider-thumb {
transition: none;
}
}@import "tailwindcss";
@theme {
--color-trs07-bg: #111318;
--color-trs07-bg: oklch(0.18 0.01 262);
--color-trs07-panel: #1a1d24;
--color-trs07-panel: oklch(0.23 0.012 262);
--color-trs07-edge: #2d3240;
--color-trs07-edge: oklch(0.32 0.018 262);
--color-trs07-copper: #b87333;
--color-trs07-copper: oklch(0.62 0.12 55);
--color-trs07-copperlit: #d4925a;
--color-trs07-copperlit: oklch(0.72 0.1 55);
--color-trs07-ink: #e2e8f0;
--color-trs07-ink: oklch(0.92 0.01 255);
--color-trs07-mut: #8a97ab;
--color-trs07-mut: oklch(0.66 0.025 255);
--font-trs07-sans: 'Space Grotesk', system-ui, sans-serif;
--font-trs07-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.trs-07 {
width: 100%;
min-height: 100svh;
}
/* Faders: the copper cap, plus the vertical appearance fallback for older
WebKit. Everything else about orientation is a utility. */
.trs-07 input[type="range"] {
-webkit-appearance: slider-vertical;
}
.trs-07 input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 30px;
height: 18px;
border-radius: 4px;
background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
border: 1px solid oklch(1 0 0 / 0.16);
box-shadow: 0 2px 8px oklch(0 0 0 / 0.5), inset 0 1px 0 oklch(1 0 0 / 0.2);
cursor: grab;
transition: box-shadow .15s;
}
.trs-07 input[type="range"]:active::-webkit-slider-thumb {
cursor: grabbing;
box-shadow: 0 0 0 4px color-mix(in oklab, var(--color-trs07-copper) 32%, transparent), 0 2px 8px oklch(0 0 0 / 0.5);
}
.trs-07 input[type="range"]::-moz-range-thumb {
width: 30px;
height: 18px;
border-radius: 4px;
background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
border: 1px solid oklch(1 0 0 / 0.16);
cursor: grab;
}
@media (prefers-reduced-motion: reduce) {
.trs-07 input[type="range"]::-webkit-slider-thumb {
transition: none;
}
}(function(){
var rack = document.getElementById('trs-07-rack');
var curve = document.getElementById('trs-07-curve-line');
var BANDS = [
{ label: '32', val: 50 }, { label: '64', val: 60 }, { label: '125', val: 70 },
{ label: '250', val: 65 }, { label: '500', val: 50 }, { label: '1K', val: 55 },
{ label: '2K', val: 60 }, { label: '4K', val: 58 }, { label: '8K', val: 50 }, { label: '16K', val: 45 }
];
var PRESETS = {
flat: [50,50,50,50,50,50,50,50,50,50],
bass: [80,78,72,65,55,48,44,42,40,38],
treble: [40,40,42,44,50,58,68,75,78,80],
vocal: [38,42,50,65,72,70,65,55,48,42]
};
var faders = [];
function db(v){ return (v - 50 >= 0 ? '+' : '') + (v - 50); }
BANDS.forEach(function(band){
var col = document.createElement('div');
col.className = 'flex flex-col items-center gap-2 w-8';
var readout = document.createElement('span');
readout.className = 'font-trs07-mono text-[10px] text-trs07-mut tabular-nums';
readout.textContent = db(band.val);
var wrap = document.createElement('div');
wrap.className = 'relative h-40 w-8 grid place-items-center';
wrap.innerHTML = '<span class="absolute w-1.5 h-full rounded-full bg-gradient-to-b from-trs07-edge to-trs07-panel shadow-[inset_2px_2px_4px_oklch(0_0_0/0.6),inset_-1px_-1px_3px_oklch(1_0_0/0.05)]" aria-hidden="true"></span>';
var inp = document.createElement('input');
inp.type = 'range'; inp.min = '0'; inp.max = '100'; inp.value = band.val;
inp.setAttribute('orient', 'vertical');
inp.setAttribute('aria-label', band.label + ' hertz band');
inp.className = 'relative z-10 w-8 h-40 appearance-none bg-transparent outline-none cursor-pointer [writing-mode:vertical-lr] [direction:rtl] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper rounded-full';
inp.addEventListener('input', function(){
readout.textContent = db(+inp.value);
inp.setAttribute('aria-valuetext', db(+inp.value) + ' decibels at ' + band.label + ' hertz');
draw();
});
wrap.appendChild(inp);
var label = document.createElement('span');
label.className = 'text-[10px] font-semibold uppercase tracking-wider text-trs07-copper';
label.textContent = band.label;
col.appendChild(readout); col.appendChild(wrap); col.appendChild(label);
rack.appendChild(col);
faders.push(inp);
});
function draw(){
var pts = faders.map(function(f, i){
var x = (i / (faders.length - 1)) * 300;
var y = 30 - ((+f.value - 50) / 50) * 26;
return x.toFixed(1) + ',' + y.toFixed(1);
});
curve.setAttribute('points', pts.join(' '));
}
document.querySelectorAll('#trs-07-presets button').forEach(function(btn){
btn.addEventListener('click', function(){
document.querySelectorAll('#trs-07-presets button').forEach(function(b){ b.setAttribute('aria-pressed', 'false'); });
btn.setAttribute('aria-pressed', 'true');
var vals = PRESETS[btn.dataset.preset];
faders.forEach(function(f, i){ f.value = vals[i]; f.dispatchEvent(new Event('input')); });
});
});
draw();
})();(function(){
var rack = document.getElementById('trs-07-rack');
var curve = document.getElementById('trs-07-curve-line');
var BANDS = [
{ label: '32', val: 50 }, { label: '64', val: 60 }, { label: '125', val: 70 },
{ label: '250', val: 65 }, { label: '500', val: 50 }, { label: '1K', val: 55 },
{ label: '2K', val: 60 }, { label: '4K', val: 58 }, { label: '8K', val: 50 }, { label: '16K', val: 45 }
];
var PRESETS = {
flat: [50,50,50,50,50,50,50,50,50,50],
bass: [80,78,72,65,55,48,44,42,40,38],
treble: [40,40,42,44,50,58,68,75,78,80],
vocal: [38,42,50,65,72,70,65,55,48,42]
};
var faders = [];
function db(v){ return (v - 50 >= 0 ? '+' : '') + (v - 50); }
BANDS.forEach(function(band){
var col = document.createElement('div');
col.className = 'flex flex-col items-center gap-2 w-8';
var readout = document.createElement('span');
readout.className = 'font-trs07-mono text-[10px] text-trs07-mut tabular-nums';
readout.textContent = db(band.val);
var wrap = document.createElement('div');
wrap.className = 'relative h-40 w-8 grid place-items-center';
wrap.innerHTML = '<span class="absolute w-1.5 h-full rounded-full bg-gradient-to-b from-trs07-edge to-trs07-panel shadow-[inset_2px_2px_4px_oklch(0_0_0/0.6),inset_-1px_-1px_3px_oklch(1_0_0/0.05)]" aria-hidden="true"></span>';
var inp = document.createElement('input');
inp.type = 'range'; inp.min = '0'; inp.max = '100'; inp.value = band.val;
inp.setAttribute('orient', 'vertical');
inp.setAttribute('aria-label', band.label + ' hertz band');
inp.className = 'relative z-10 w-8 h-40 appearance-none bg-transparent outline-none cursor-pointer [writing-mode:vertical-lr] [direction:rtl] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper rounded-full';
inp.addEventListener('input', function(){
readout.textContent = db(+inp.value);
inp.setAttribute('aria-valuetext', db(+inp.value) + ' decibels at ' + band.label + ' hertz');
draw();
});
wrap.appendChild(inp);
var label = document.createElement('span');
label.className = 'text-[10px] font-semibold uppercase tracking-wider text-trs07-copper';
label.textContent = band.label;
col.appendChild(readout); col.appendChild(wrap); col.appendChild(label);
rack.appendChild(col);
faders.push(inp);
});
function draw(){
var pts = faders.map(function(f, i){
var x = (i / (faders.length - 1)) * 300;
var y = 30 - ((+f.value - 50) / 50) * 26;
return x.toFixed(1) + ',' + y.toFixed(1);
});
curve.setAttribute('points', pts.join(' '));
}
document.querySelectorAll('#trs-07-presets button').forEach(function(btn){
btn.addEventListener('click', function(){
document.querySelectorAll('#trs-07-presets button').forEach(function(b){ b.setAttribute('aria-pressed', 'false'); });
btn.setAttribute('aria-pressed', 'true');
var vals = PRESETS[btn.dataset.preset];
faders.forEach(function(f, i){ f.value = vals[i]; f.dispatchEvent(new Event('input')); });
});
});
draw();
})();Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-trs07-bg: #111318;
--color-trs07-bg: oklch(0.18 0.01 262);
--color-trs07-panel: #1a1d24;
--color-trs07-panel: oklch(0.23 0.012 262);
--color-trs07-edge: #2d3240;
--color-trs07-edge: oklch(0.32 0.018 262);
--color-trs07-copper: #b87333;
--color-trs07-copper: oklch(0.62 0.12 55);
--color-trs07-copperlit: #d4925a;
--color-trs07-copperlit: oklch(0.72 0.1 55);
--color-trs07-ink: #e2e8f0;
--color-trs07-ink: oklch(0.92 0.01 255);
--color-trs07-mut: #8a97ab;
--color-trs07-mut: oklch(0.66 0.025 255);
--font-trs07-sans: 'Space Grotesk', system-ui, sans-serif;
--font-trs07-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.trs-07 {
width: 100%;
min-height: 100svh;
}
/* Faders: the copper cap, plus the vertical appearance fallback for older
WebKit. Everything else about orientation is a utility. */
.trs-07 input[type="range"] {
-webkit-appearance: slider-vertical;
}
.trs-07 input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 30px;
height: 18px;
border-radius: 4px;
background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
border: 1px solid oklch(1 0 0 / 0.16);
box-shadow: 0 2px 8px oklch(0 0 0 / 0.5), inset 0 1px 0 oklch(1 0 0 / 0.2);
cursor: grab;
transition: box-shadow .15s;
}
.trs-07 input[type="range"]:active::-webkit-slider-thumb {
cursor: grabbing;
box-shadow: 0 0 0 4px color-mix(in oklab, var(--color-trs07-copper) 32%, transparent), 0 2px 8px oklch(0 0 0 / 0.5);
}
.trs-07 input[type="range"]::-moz-range-thumb {
width: 30px;
height: 18px;
border-radius: 4px;
background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
border: 1px solid oklch(1 0 0 / 0.16);
cursor: grab;
}
@media (prefers-reduced-motion: reduce) {
.trs-07 input[type="range"]::-webkit-slider-thumb {
transition: none;
}
}@import "tailwindcss";
@theme {
--color-trs07-bg: #111318;
--color-trs07-bg: oklch(0.18 0.01 262);
--color-trs07-panel: #1a1d24;
--color-trs07-panel: oklch(0.23 0.012 262);
--color-trs07-edge: #2d3240;
--color-trs07-edge: oklch(0.32 0.018 262);
--color-trs07-copper: #b87333;
--color-trs07-copper: oklch(0.62 0.12 55);
--color-trs07-copperlit: #d4925a;
--color-trs07-copperlit: oklch(0.72 0.1 55);
--color-trs07-ink: #e2e8f0;
--color-trs07-ink: oklch(0.92 0.01 255);
--color-trs07-mut: #8a97ab;
--color-trs07-mut: oklch(0.66 0.025 255);
--font-trs07-sans: 'Space Grotesk', system-ui, sans-serif;
--font-trs07-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.trs-07 {
width: 100%;
min-height: 100svh;
}
/* Faders: the copper cap, plus the vertical appearance fallback for older
WebKit. Everything else about orientation is a utility. */
.trs-07 input[type="range"] {
-webkit-appearance: slider-vertical;
}
.trs-07 input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 30px;
height: 18px;
border-radius: 4px;
background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
border: 1px solid oklch(1 0 0 / 0.16);
box-shadow: 0 2px 8px oklch(0 0 0 / 0.5), inset 0 1px 0 oklch(1 0 0 / 0.2);
cursor: grab;
transition: box-shadow .15s;
}
.trs-07 input[type="range"]:active::-webkit-slider-thumb {
cursor: grabbing;
box-shadow: 0 0 0 4px color-mix(in oklab, var(--color-trs07-copper) 32%, transparent), 0 2px 8px oklch(0 0 0 / 0.5);
}
.trs-07 input[type="range"]::-moz-range-thumb {
width: 30px;
height: 18px;
border-radius: 4px;
background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
border: 1px solid oklch(1 0 0 / 0.16);
cursor: grab;
}
@media (prefers-reduced-motion: reduce) {
.trs-07 input[type="range"]::-webkit-slider-thumb {
transition: none;
}
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;600&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;600&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Orientation became two arbitrary utilities (
[writing-mode:vertical-lr] [direction:rtl]) on the input, with the legacyappearance:slider-verticalkept in CSS where it belongs. - The groove is a sibling span carrying one inset
shadow-[…], so the input needs no background and no stacking tricks beyondrelative z-10. - UI upgrade: a live SVG frequency-response curve above the rack, preset chips using
aria-pressedinstead of an.activeclass, 44px preset targets, and per-bandaria-valuetextin decibels.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind CSS Vertical Range Sliders — 10-Band Audio Equalizer
Source: https://codefronts.com/components/tailwind-css-range-sliders/tailwind-vertical-range-sliders-audio-equalizer/
Ten copper faders in inset steel grooves, dB readouts per band, four presets — and a live SVG response curve above the rack that the CSS original only listed as a "customization". Vertical orientation is one arbitrary utility pair now: [writing-mode:vertical-lr] [direction:rtl].
## HTML
```html
<section class="trs-07 w-full min-h-svh grid place-items-center bg-trs07-bg font-trs07-sans px-5 py-10">
<div class="w-[min(520px,100%)] rounded-3xl bg-trs07-panel border border-trs07-edge p-8 shadow-[0_24px_70px_-26px_oklch(0_0_0/0.85)]">
<header class="flex items-center justify-between gap-4 mb-6">
<h3 class="text-sm font-bold uppercase tracking-[0.2em] text-trs07-ink m-0">Equalizer</h3>
<div class="flex gap-1.5" aria-hidden="true">
<span class="size-2 rounded-full bg-[#ff5f57] shadow-[0_0_6px_#ff5f57]"></span>
<span class="size-2 rounded-full bg-[#febc2e] shadow-[0_0_6px_#febc2e]"></span>
<span class="size-2 rounded-full bg-[#28c840] shadow-[0_0_6px_#28c840]"></span>
</div>
</header>
<svg viewBox="0 0 300 60" class="w-full h-14 mb-2 overflow-visible" aria-hidden="true">
<defs>
<linearGradient id="trs-07-curve" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="var(--color-trs07-copper)"/>
<stop offset="100%" stop-color="var(--color-trs07-copperlit)"/>
</linearGradient>
</defs>
<line x1="0" y1="30" x2="300" y2="30" class="stroke-trs07-edge" stroke-width="1" stroke-dasharray="3 4"/>
<polyline id="trs-07-curve-line" fill="none" stroke="url(#trs-07-curve)" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round" points=""/>
</svg>
<div class="flex justify-between items-end h-52 mb-4" id="trs-07-rack" role="group" aria-label="Frequency bands"></div>
<div class="flex flex-wrap gap-2 pt-4 border-t border-trs07-edge" id="trs-07-presets" role="group" aria-label="Equalizer presets">
<button type="button" data-preset="flat" aria-pressed="true" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Flat</button>
<button type="button" data-preset="bass" aria-pressed="false" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Bass boost</button>
<button type="button" data-preset="treble" aria-pressed="false" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Treble</button>
<button type="button" data-preset="vocal" aria-pressed="false" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Vocal</button>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-trs07-bg: #111318;
--color-trs07-bg: oklch(0.18 0.01 262);
--color-trs07-panel: #1a1d24;
--color-trs07-panel: oklch(0.23 0.012 262);
--color-trs07-edge: #2d3240;
--color-trs07-edge: oklch(0.32 0.018 262);
--color-trs07-copper: #b87333;
--color-trs07-copper: oklch(0.62 0.12 55);
--color-trs07-copperlit: #d4925a;
--color-trs07-copperlit: oklch(0.72 0.1 55);
--color-trs07-ink: #e2e8f0;
--color-trs07-ink: oklch(0.92 0.01 255);
--color-trs07-mut: #8a97ab;
--color-trs07-mut: oklch(0.66 0.025 255);
--font-trs07-sans: 'Space Grotesk', system-ui, sans-serif;
--font-trs07-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.trs-07 {
width: 100%;
min-height: 100svh;
}
/* Faders: the copper cap, plus the vertical appearance fallback for older
WebKit. Everything else about orientation is a utility. */
.trs-07 input[type="range"] {
-webkit-appearance: slider-vertical;
}
.trs-07 input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 30px;
height: 18px;
border-radius: 4px;
background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
border: 1px solid oklch(1 0 0 / 0.16);
box-shadow: 0 2px 8px oklch(0 0 0 / 0.5), inset 0 1px 0 oklch(1 0 0 / 0.2);
cursor: grab;
transition: box-shadow .15s;
}
.trs-07 input[type="range"]:active::-webkit-slider-thumb {
cursor: grabbing;
box-shadow: 0 0 0 4px color-mix(in oklab, var(--color-trs07-copper) 32%, transparent), 0 2px 8px oklch(0 0 0 / 0.5);
}
.trs-07 input[type="range"]::-moz-range-thumb {
width: 30px;
height: 18px;
border-radius: 4px;
background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
border: 1px solid oklch(1 0 0 / 0.16);
cursor: grab;
}
@media (prefers-reduced-motion: reduce) {
.trs-07 input[type="range"]::-webkit-slider-thumb {
transition: none;
}
}
```
## JavaScript
```js
(function(){
var rack = document.getElementById('trs-07-rack');
var curve = document.getElementById('trs-07-curve-line');
var BANDS = [
{ label: '32', val: 50 }, { label: '64', val: 60 }, { label: '125', val: 70 },
{ label: '250', val: 65 }, { label: '500', val: 50 }, { label: '1K', val: 55 },
{ label: '2K', val: 60 }, { label: '4K', val: 58 }, { label: '8K', val: 50 }, { label: '16K', val: 45 }
];
var PRESETS = {
flat: [50,50,50,50,50,50,50,50,50,50],
bass: [80,78,72,65,55,48,44,42,40,38],
treble: [40,40,42,44,50,58,68,75,78,80],
vocal: [38,42,50,65,72,70,65,55,48,42]
};
var faders = [];
function db(v){ return (v - 50 >= 0 ? '+' : '') + (v - 50); }
BANDS.forEach(function(band){
var col = document.createElement('div');
col.className = 'flex flex-col items-center gap-2 w-8';
var readout = document.createElement('span');
readout.className = 'font-trs07-mono text-[10px] text-trs07-mut tabular-nums';
readout.textContent = db(band.val);
var wrap = document.createElement('div');
wrap.className = 'relative h-40 w-8 grid place-items-center';
wrap.innerHTML = '<span class="absolute w-1.5 h-full rounded-full bg-gradient-to-b from-trs07-edge to-trs07-panel shadow-[inset_2px_2px_4px_oklch(0_0_0/0.6),inset_-1px_-1px_3px_oklch(1_0_0/0.05)]" aria-hidden="true"></span>';
var inp = document.createElement('input');
inp.type = 'range'; inp.min = '0'; inp.max = '100'; inp.value = band.val;
inp.setAttribute('orient', 'vertical');
inp.setAttribute('aria-label', band.label + ' hertz band');
inp.className = 'relative z-10 w-8 h-40 appearance-none bg-transparent outline-none cursor-pointer [writing-mode:vertical-lr] [direction:rtl] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper rounded-full';
inp.addEventListener('input', function(){
readout.textContent = db(+inp.value);
inp.setAttribute('aria-valuetext', db(+inp.value) + ' decibels at ' + band.label + ' hertz');
draw();
});
wrap.appendChild(inp);
var label = document.createElement('span');
label.className = 'text-[10px] font-semibold uppercase tracking-wider text-trs07-copper';
label.textContent = band.label;
col.appendChild(readout); col.appendChild(wrap); col.appendChild(label);
rack.appendChild(col);
faders.push(inp);
});
function draw(){
var pts = faders.map(function(f, i){
var x = (i / (faders.length - 1)) * 300;
var y = 30 - ((+f.value - 50) / 50) * 26;
return x.toFixed(1) + ',' + y.toFixed(1);
});
curve.setAttribute('points', pts.join(' '));
}
document.querySelectorAll('#trs-07-presets button').forEach(function(btn){
btn.addEventListener('click', function(){
document.querySelectorAll('#trs-07-presets button').forEach(function(b){ b.setAttribute('aria-pressed', 'false'); });
btn.setAttribute('aria-pressed', 'true');
var vals = PRESETS[btn.dataset.preset];
faders.forEach(function(f, i){ f.value = vals[i]; f.dispatchEvent(new Event('input')); });
});
});
draw();
})();
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind CSS Vertical Range Sliders — 10-Band Audio Equalizer
Source: https://codefronts.com/components/tailwind-css-range-sliders/tailwind-vertical-range-sliders-audio-equalizer/
Ten copper faders in inset steel grooves, dB readouts per band, four presets — and a live SVG response curve above the rack that the CSS original only listed as a "customization". Vertical orientation is one arbitrary utility pair now: [writing-mode:vertical-lr] [direction:rtl].
## HTML
```html
<section class="trs-07 w-full min-h-svh grid place-items-center bg-trs07-bg font-trs07-sans px-5 py-10">
<div class="w-[min(520px,100%)] rounded-3xl bg-trs07-panel border border-trs07-edge p-8 shadow-[0_24px_70px_-26px_oklch(0_0_0/0.85)]">
<header class="flex items-center justify-between gap-4 mb-6">
<h3 class="text-sm font-bold uppercase tracking-[0.2em] text-trs07-ink m-0">Equalizer</h3>
<div class="flex gap-1.5" aria-hidden="true">
<span class="size-2 rounded-full bg-[#ff5f57] shadow-[0_0_6px_#ff5f57]"></span>
<span class="size-2 rounded-full bg-[#febc2e] shadow-[0_0_6px_#febc2e]"></span>
<span class="size-2 rounded-full bg-[#28c840] shadow-[0_0_6px_#28c840]"></span>
</div>
</header>
<svg viewBox="0 0 300 60" class="w-full h-14 mb-2 overflow-visible" aria-hidden="true">
<defs>
<linearGradient id="trs-07-curve" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="var(--color-trs07-copper)"/>
<stop offset="100%" stop-color="var(--color-trs07-copperlit)"/>
</linearGradient>
</defs>
<line x1="0" y1="30" x2="300" y2="30" class="stroke-trs07-edge" stroke-width="1" stroke-dasharray="3 4"/>
<polyline id="trs-07-curve-line" fill="none" stroke="url(#trs-07-curve)" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round" points=""/>
</svg>
<div class="flex justify-between items-end h-52 mb-4" id="trs-07-rack" role="group" aria-label="Frequency bands"></div>
<div class="flex flex-wrap gap-2 pt-4 border-t border-trs07-edge" id="trs-07-presets" role="group" aria-label="Equalizer presets">
<button type="button" data-preset="flat" aria-pressed="true" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Flat</button>
<button type="button" data-preset="bass" aria-pressed="false" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Bass boost</button>
<button type="button" data-preset="treble" aria-pressed="false" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Treble</button>
<button type="button" data-preset="vocal" aria-pressed="false" class="min-h-11 rounded-full border border-trs07-edge bg-transparent px-4 text-[11px] font-semibold text-trs07-mut transition-colors duration-200 hover:border-trs07-copper hover:text-trs07-copper aria-pressed:border-trs07-copper aria-pressed:bg-trs07-copper/12 aria-pressed:text-trs07-copperlit focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper motion-reduce:transition-none">Vocal</button>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-trs07-bg: #111318;
--color-trs07-bg: oklch(0.18 0.01 262);
--color-trs07-panel: #1a1d24;
--color-trs07-panel: oklch(0.23 0.012 262);
--color-trs07-edge: #2d3240;
--color-trs07-edge: oklch(0.32 0.018 262);
--color-trs07-copper: #b87333;
--color-trs07-copper: oklch(0.62 0.12 55);
--color-trs07-copperlit: #d4925a;
--color-trs07-copperlit: oklch(0.72 0.1 55);
--color-trs07-ink: #e2e8f0;
--color-trs07-ink: oklch(0.92 0.01 255);
--color-trs07-mut: #8a97ab;
--color-trs07-mut: oklch(0.66 0.025 255);
--font-trs07-sans: 'Space Grotesk', system-ui, sans-serif;
--font-trs07-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.trs-07 {
width: 100%;
min-height: 100svh;
}
/* Faders: the copper cap, plus the vertical appearance fallback for older
WebKit. Everything else about orientation is a utility. */
.trs-07 input[type="range"] {
-webkit-appearance: slider-vertical;
}
.trs-07 input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 30px;
height: 18px;
border-radius: 4px;
background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
border: 1px solid oklch(1 0 0 / 0.16);
box-shadow: 0 2px 8px oklch(0 0 0 / 0.5), inset 0 1px 0 oklch(1 0 0 / 0.2);
cursor: grab;
transition: box-shadow .15s;
}
.trs-07 input[type="range"]:active::-webkit-slider-thumb {
cursor: grabbing;
box-shadow: 0 0 0 4px color-mix(in oklab, var(--color-trs07-copper) 32%, transparent), 0 2px 8px oklch(0 0 0 / 0.5);
}
.trs-07 input[type="range"]::-moz-range-thumb {
width: 30px;
height: 18px;
border-radius: 4px;
background: linear-gradient(180deg, #c8a07a 0%, #8b5e3c 50%, #c8a07a 100%);
border: 1px solid oklch(1 0 0 / 0.16);
cursor: grab;
}
@media (prefers-reduced-motion: reduce) {
.trs-07 input[type="range"]::-webkit-slider-thumb {
transition: none;
}
}
```
## JavaScript
```js
(function(){
var rack = document.getElementById('trs-07-rack');
var curve = document.getElementById('trs-07-curve-line');
var BANDS = [
{ label: '32', val: 50 }, { label: '64', val: 60 }, { label: '125', val: 70 },
{ label: '250', val: 65 }, { label: '500', val: 50 }, { label: '1K', val: 55 },
{ label: '2K', val: 60 }, { label: '4K', val: 58 }, { label: '8K', val: 50 }, { label: '16K', val: 45 }
];
var PRESETS = {
flat: [50,50,50,50,50,50,50,50,50,50],
bass: [80,78,72,65,55,48,44,42,40,38],
treble: [40,40,42,44,50,58,68,75,78,80],
vocal: [38,42,50,65,72,70,65,55,48,42]
};
var faders = [];
function db(v){ return (v - 50 >= 0 ? '+' : '') + (v - 50); }
BANDS.forEach(function(band){
var col = document.createElement('div');
col.className = 'flex flex-col items-center gap-2 w-8';
var readout = document.createElement('span');
readout.className = 'font-trs07-mono text-[10px] text-trs07-mut tabular-nums';
readout.textContent = db(band.val);
var wrap = document.createElement('div');
wrap.className = 'relative h-40 w-8 grid place-items-center';
wrap.innerHTML = '<span class="absolute w-1.5 h-full rounded-full bg-gradient-to-b from-trs07-edge to-trs07-panel shadow-[inset_2px_2px_4px_oklch(0_0_0/0.6),inset_-1px_-1px_3px_oklch(1_0_0/0.05)]" aria-hidden="true"></span>';
var inp = document.createElement('input');
inp.type = 'range'; inp.min = '0'; inp.max = '100'; inp.value = band.val;
inp.setAttribute('orient', 'vertical');
inp.setAttribute('aria-label', band.label + ' hertz band');
inp.className = 'relative z-10 w-8 h-40 appearance-none bg-transparent outline-none cursor-pointer [writing-mode:vertical-lr] [direction:rtl] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-trs07-copper rounded-full';
inp.addEventListener('input', function(){
readout.textContent = db(+inp.value);
inp.setAttribute('aria-valuetext', db(+inp.value) + ' decibels at ' + band.label + ' hertz');
draw();
});
wrap.appendChild(inp);
var label = document.createElement('span');
label.className = 'text-[10px] font-semibold uppercase tracking-wider text-trs07-copper';
label.textContent = band.label;
col.appendChild(readout); col.appendChild(wrap); col.appendChild(label);
rack.appendChild(col);
faders.push(inp);
});
function draw(){
var pts = faders.map(function(f, i){
var x = (i / (faders.length - 1)) * 300;
var y = 30 - ((+f.value - 50) / 50) * 26;
return x.toFixed(1) + ',' + y.toFixed(1);
});
curve.setAttribute('points', pts.join(' '));
}
document.querySelectorAll('#trs-07-presets button').forEach(function(btn){
btn.addEventListener('click', function(){
document.querySelectorAll('#trs-07-presets button').forEach(function(b){ b.setAttribute('aria-pressed', 'false'); });
btn.setAttribute('aria-pressed', 'true');
var vals = PRESETS[btn.dataset.preset];
faders.forEach(function(f, i){ f.value = vals[i]; f.dispatchEvent(new Event('input')); });
});
});
draw();
})();
```How this works
Vertical is a writing mode, not a transform. [writing-mode:vertical-lr] plus [direction:rtl] makes up = more; orient="vertical" stays on the element for older Firefox, and [appearance:slider-vertical] covers older WebKit. The groove behind each fader is a separate absolutely-positioned span so the input itself needs no background.
Presets are a single dispatch. Setting .value and firing new Event('input') on each band means the readouts, the curve and the chips all update through the same handler as a manual drag — no duplicated formatting logic.
The curve is the upgrade. Ten numbers are hard to read as a shape; a smoothed polyline across the top turns the rack into an EQ you can judge at a glance, and it is aria-hidden because the per-band dB values are already announced.
Make it yours
- Bands: push to
BANDS— the flex row and the curve both derive from its length. - Metal: swap the thumb gradient (copper →
#e8e8e8/#999for silver) in the thumb block. - Web Audio: map each band to a
BiquadFilterNodewithgain.value = (v-50)/50*12.
Gotchas — read before shipping
- Vertical range inputs still differ across engines. Test that drag-up increases; if a target browser disagrees, the fallback is
rotate-[-90deg]with swapped width/height. orient="vertical"is non-standard HTML but harmless everywhere and required by older Firefox — always include it.- Safari can render vertical inputs wider than declared; the channel column sets an explicit width so the rack cannot overflow.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Vertical sliders are the narrow part: modern engines honour writing-mode, older ones need appearance:slider-vertical and orient — both shipped here.