Tailwind + JSMIT licensed

Tailwind CSS Brutalist Range Slider with Thick Block Track

Brutalism as a system: 3px black rules, zero-blur offset shadows, one red block for a thumb and no rounded corners anywhere. The port suits it — shadow-[6px_6px_0_var(--color-trs11-ink)] and border-[3px] say the whole aesthetic, and the preset row is a real segmented control.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="trs-11 w-full min-h-svh grid place-items-center bg-trs11-bg font-trs11-mono px-6 py-12" id="trs-11-root" style="--v:.64">
  <div class="w-[min(440px,100%)] bg-trs11-card border-[3px] border-trs11-ink shadow-[6px_6px_0_var(--color-trs11-ink)]">
    <header class="flex items-center justify-between gap-4 bg-trs11-ink px-5 py-2.5 text-white">
      <span class="text-xs font-bold uppercase tracking-[0.2em]">CONFIG.SYS</span>
      <span class="flex gap-1.5" aria-hidden="true"><span class="size-2.5 rounded-full bg-white/30"></span><span class="size-2.5 rounded-full bg-white/30"></span><span class="size-2.5 rounded-full bg-white/30"></span></span>
    </header>

    <div class="p-8">
      <div class="mb-6">
        <div class="text-[80px] leading-none font-bold tracking-tighter text-trs11-ink tabular-nums" id="trs-11-num">64</div>
        <div class="text-xs uppercase tracking-[0.2em] text-trs11-mut mt-1">Allocation units</div>
      </div>

      <div class="relative h-8 border-[3px] border-trs11-ink bg-trs11-grey mb-2">
        <div class="absolute inset-y-0 left-0 bg-trs11-ink w-[calc(var(--v)*100%)] transition-none"></div>
        <input type="range" min="0" max="100" step="4" value="64" id="trs-11-inp" aria-label="Allocation units"
               class="absolute inset-0 w-full h-full appearance-none bg-transparent outline-none cursor-ew-resize z-10 focus-visible:outline-[3px] focus-visible:outline-offset-4 focus-visible:outline-trs11-hot">
      </div>

      <div class="flex justify-between text-[10px] text-trs11-mut mb-7">
        <span class="flex flex-col items-center"><span class="text-trs11-ink text-xs" aria-hidden="true">|</span>0</span>
        <span class="flex flex-col items-center"><span class="text-trs11-ink text-xs" aria-hidden="true">|</span>25</span>
        <span class="flex flex-col items-center"><span class="text-trs11-ink text-xs" aria-hidden="true">|</span>50</span>
        <span class="flex flex-col items-center"><span class="text-trs11-ink text-xs" aria-hidden="true">|</span>75</span>
        <span class="flex flex-col items-center"><span class="text-trs11-ink text-xs" aria-hidden="true">|</span>100</span>
      </div>

      <div class="flex" role="group" aria-label="Presets" id="trs-11-presets">
        <button type="button" data-val="0" aria-pressed="false" class="flex-1 min-h-11 border-[3px] border-trs11-ink bg-transparent text-xs font-bold uppercase tracking-wider text-trs11-ink transition-colors duration-150 hover:bg-trs11-ink hover:text-white aria-pressed:bg-trs11-ink aria-pressed:text-white focus-visible:outline-[3px] focus-visible:outline-offset-2 focus-visible:outline-trs11-hot">Reset</button>
        <button type="button" data-val="50" aria-pressed="false" class="flex-1 min-h-11 border-[3px] border-l-0 border-trs11-ink bg-transparent text-xs font-bold uppercase tracking-wider text-trs11-ink transition-colors duration-150 hover:bg-trs11-ink hover:text-white aria-pressed:bg-trs11-ink aria-pressed:text-white focus-visible:outline-[3px] focus-visible:outline-offset-2 focus-visible:outline-trs11-hot">Half</button>
        <button type="button" data-val="64" aria-pressed="true" class="flex-1 min-h-11 border-[3px] border-l-0 border-trs11-ink bg-transparent text-xs font-bold uppercase tracking-wider text-trs11-ink transition-colors duration-150 hover:bg-trs11-ink hover:text-white aria-pressed:bg-trs11-ink aria-pressed:text-white focus-visible:outline-[3px] focus-visible:outline-offset-2 focus-visible:outline-trs11-hot">Default</button>
        <button type="button" data-val="100" aria-pressed="false" class="flex-1 min-h-11 border-[3px] border-l-0 border-trs11-ink bg-transparent text-xs font-bold uppercase tracking-wider text-trs11-ink transition-colors duration-150 hover:bg-trs11-ink hover:text-white aria-pressed:bg-trs11-ink aria-pressed:text-white focus-visible:outline-[3px] focus-visible:outline-offset-2 focus-visible:outline-trs11-hot">Max</button>
      </div>

      <p class="text-[10px] uppercase tracking-[0.15em] text-trs11-mut mt-5 m-0">Keys: 1-9 set 10-90% · 0 sets 100% · ← → step</p>
    </div>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-trs11-bg: #f5f0e8;
  --color-trs11-bg: oklch(0.95 0.018 85);
  --color-trs11-card: #ece6da;
  --color-trs11-card: oklch(0.92 0.02 85);
  --color-trs11-grey: #cdc7bb;
  --color-trs11-grey: oklch(0.82 0.015 85);
  --color-trs11-ink: #111111;
  --color-trs11-ink: oklch(0.15 0 0);
  --color-trs11-hot: #d63427;
  --color-trs11-hot: oklch(0.55 0.21 27);
  --color-trs11-mut: #6f6a61;
  --color-trs11-mut: oklch(0.52 0.012 85);
  --font-trs11-mono: 'Space Mono', ui-monospace, monospace;
}

@property --v {
  syntax: "<number>";
  inherits: true;
  initial-value: 0.64;
}

.trs-11 {
  width: 100%;
  min-height: 100svh;
}
/* The block thumb: square, full track height, hard black right edge. */

.trs-11 input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 28px;
  height: 26px;
  border: 0;
  border-radius: 0;
  border-right: 3px solid var(--color-trs11-ink);
  background: var(--color-trs11-hot);
  cursor: ew-resize;
  transition: background .15s;
}

.trs-11 input[type="range"]:hover::-webkit-slider-thumb {
  background: oklch(0.62 0.22 27);
}

.trs-11 input[type="range"]::-moz-range-thumb {
  width: 28px;
  height: 26px;
  border: 0;
  border-radius: 0;
  background: var(--color-trs11-hot);
  cursor: ew-resize;
}

@media (prefers-reduced-motion: reduce) {
  .trs-11 input[type="range"]::-webkit-slider-thumb {
    transition: none;
  }
}
(function(){
  var root = document.getElementById('trs-11-root');
  var inp = document.getElementById('trs-11-inp');
  var num = document.getElementById('trs-11-num');
  var buttons = Array.prototype.slice.call(document.querySelectorAll('#trs-11-presets button'));

  function update(){
    var v = +inp.value;
    root.style.setProperty('--v', v / 100);
    num.textContent = v;
    buttons.forEach(function(b){ b.setAttribute('aria-pressed', String(+b.dataset.val === v)); });
  }
  inp.addEventListener('input', update);
  buttons.forEach(function(b){
    b.addEventListener('click', function(){ inp.value = b.dataset.val; update(); });
  });
  document.addEventListener('keydown', function(e){
    if (e.target.tagName === 'INPUT' && e.target !== inp) return;
    if (e.key >= '1' && e.key <= '9') { inp.value = +e.key * 10; update(); }
    else if (e.key === '0') { inp.value = 100; update(); }
  });
  update();
})();

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<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.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-trs11-bg: #f5f0e8;
  --color-trs11-bg: oklch(0.95 0.018 85);
  --color-trs11-card: #ece6da;
  --color-trs11-card: oklch(0.92 0.02 85);
  --color-trs11-grey: #cdc7bb;
  --color-trs11-grey: oklch(0.82 0.015 85);
  --color-trs11-ink: #111111;
  --color-trs11-ink: oklch(0.15 0 0);
  --color-trs11-hot: #d63427;
  --color-trs11-hot: oklch(0.55 0.21 27);
  --color-trs11-mut: #6f6a61;
  --color-trs11-mut: oklch(0.52 0.012 85);
  --font-trs11-mono: 'Space Mono', ui-monospace, monospace;
}

@property --v {
  syntax: "<number>";
  inherits: true;
  initial-value: 0.64;
}

.trs-11 {
  width: 100%;
  min-height: 100svh;
}
/* The block thumb: square, full track height, hard black right edge. */

.trs-11 input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 28px;
  height: 26px;
  border: 0;
  border-radius: 0;
  border-right: 3px solid var(--color-trs11-ink);
  background: var(--color-trs11-hot);
  cursor: ew-resize;
  transition: background .15s;
}

.trs-11 input[type="range"]:hover::-webkit-slider-thumb {
  background: oklch(0.62 0.22 27);
}

.trs-11 input[type="range"]::-moz-range-thumb {
  width: 28px;
  height: 26px;
  border: 0;
  border-radius: 0;
  background: var(--color-trs11-hot);
  cursor: ew-resize;
}

@media (prefers-reduced-motion: reduce) {
  .trs-11 input[type="range"]::-webkit-slider-thumb {
    transition: none;
  }
}
3Fonts used by this demooptional — skip if you have your own type stack
<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+Mono:wght@400;700&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • The brutalist shadow, border weight and square geometry are all arbitrary-value utilities, which suits a style built from three literal numbers rather than a scale.
  • .active on the preset buttons became aria-pressed plus an aria-pressed: variant — the state is now announced instead of merely painted.
  • UI upgrade: digit keyboard shortcuts with an on-screen legend, presets that stay in sync when you drag past them, 44px targets, and step="4" for a deliberately mechanical feel.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
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 Brutalist Range Slider with Thick Block Track
Source: https://codefronts.com/components/tailwind-css-range-sliders/tailwind-brutalist-range-slider-thick-block/

Brutalism as a system: 3px black rules, zero-blur offset shadows, one red block for a thumb and no rounded corners anywhere. The port suits it — shadow-[6px_6px_0_var(--color-trs11-ink)] and border-[3px] say the whole aesthetic, and the preset row is a real segmented control.
## HTML
```html
<section class="trs-11 w-full min-h-svh grid place-items-center bg-trs11-bg font-trs11-mono px-6 py-12" id="trs-11-root" style="--v:.64">
  <div class="w-[min(440px,100%)] bg-trs11-card border-[3px] border-trs11-ink shadow-[6px_6px_0_var(--color-trs11-ink)]">
    <header class="flex items-center justify-between gap-4 bg-trs11-ink px-5 py-2.5 text-white">
      <span class="text-xs font-bold uppercase tracking-[0.2em]">CONFIG.SYS</span>
      <span class="flex gap-1.5" aria-hidden="true"><span class="size-2.5 rounded-full bg-white/30"></span><span class="size-2.5 rounded-full bg-white/30"></span><span class="size-2.5 rounded-full bg-white/30"></span></span>
    </header>

    <div class="p-8">
      <div class="mb-6">
        <div class="text-[80px] leading-none font-bold tracking-tighter text-trs11-ink tabular-nums" id="trs-11-num">64</div>
        <div class="text-xs uppercase tracking-[0.2em] text-trs11-mut mt-1">Allocation units</div>
      </div>

      <div class="relative h-8 border-[3px] border-trs11-ink bg-trs11-grey mb-2">
        <div class="absolute inset-y-0 left-0 bg-trs11-ink w-[calc(var(--v)*100%)] transition-none"></div>
        <input type="range" min="0" max="100" step="4" value="64" id="trs-11-inp" aria-label="Allocation units"
               class="absolute inset-0 w-full h-full appearance-none bg-transparent outline-none cursor-ew-resize z-10 focus-visible:outline-[3px] focus-visible:outline-offset-4 focus-visible:outline-trs11-hot">
      </div>

      <div class="flex justify-between text-[10px] text-trs11-mut mb-7">
        <span class="flex flex-col items-center"><span class="text-trs11-ink text-xs" aria-hidden="true">|</span>0</span>
        <span class="flex flex-col items-center"><span class="text-trs11-ink text-xs" aria-hidden="true">|</span>25</span>
        <span class="flex flex-col items-center"><span class="text-trs11-ink text-xs" aria-hidden="true">|</span>50</span>
        <span class="flex flex-col items-center"><span class="text-trs11-ink text-xs" aria-hidden="true">|</span>75</span>
        <span class="flex flex-col items-center"><span class="text-trs11-ink text-xs" aria-hidden="true">|</span>100</span>
      </div>

      <div class="flex" role="group" aria-label="Presets" id="trs-11-presets">
        <button type="button" data-val="0" aria-pressed="false" class="flex-1 min-h-11 border-[3px] border-trs11-ink bg-transparent text-xs font-bold uppercase tracking-wider text-trs11-ink transition-colors duration-150 hover:bg-trs11-ink hover:text-white aria-pressed:bg-trs11-ink aria-pressed:text-white focus-visible:outline-[3px] focus-visible:outline-offset-2 focus-visible:outline-trs11-hot">Reset</button>
        <button type="button" data-val="50" aria-pressed="false" class="flex-1 min-h-11 border-[3px] border-l-0 border-trs11-ink bg-transparent text-xs font-bold uppercase tracking-wider text-trs11-ink transition-colors duration-150 hover:bg-trs11-ink hover:text-white aria-pressed:bg-trs11-ink aria-pressed:text-white focus-visible:outline-[3px] focus-visible:outline-offset-2 focus-visible:outline-trs11-hot">Half</button>
        <button type="button" data-val="64" aria-pressed="true" class="flex-1 min-h-11 border-[3px] border-l-0 border-trs11-ink bg-transparent text-xs font-bold uppercase tracking-wider text-trs11-ink transition-colors duration-150 hover:bg-trs11-ink hover:text-white aria-pressed:bg-trs11-ink aria-pressed:text-white focus-visible:outline-[3px] focus-visible:outline-offset-2 focus-visible:outline-trs11-hot">Default</button>
        <button type="button" data-val="100" aria-pressed="false" class="flex-1 min-h-11 border-[3px] border-l-0 border-trs11-ink bg-transparent text-xs font-bold uppercase tracking-wider text-trs11-ink transition-colors duration-150 hover:bg-trs11-ink hover:text-white aria-pressed:bg-trs11-ink aria-pressed:text-white focus-visible:outline-[3px] focus-visible:outline-offset-2 focus-visible:outline-trs11-hot">Max</button>
      </div>

      <p class="text-[10px] uppercase tracking-[0.15em] text-trs11-mut mt-5 m-0">Keys: 1-9 set 10-90% · 0 sets 100% · ← → step</p>
    </div>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-trs11-bg: #f5f0e8;
  --color-trs11-bg: oklch(0.95 0.018 85);
  --color-trs11-card: #ece6da;
  --color-trs11-card: oklch(0.92 0.02 85);
  --color-trs11-grey: #cdc7bb;
  --color-trs11-grey: oklch(0.82 0.015 85);
  --color-trs11-ink: #111111;
  --color-trs11-ink: oklch(0.15 0 0);
  --color-trs11-hot: #d63427;
  --color-trs11-hot: oklch(0.55 0.21 27);
  --color-trs11-mut: #6f6a61;
  --color-trs11-mut: oklch(0.52 0.012 85);
  --font-trs11-mono: 'Space Mono', ui-monospace, monospace;
}

@property --v {
  syntax: "<number>";
  inherits: true;
  initial-value: 0.64;
}

.trs-11 {
  width: 100%;
  min-height: 100svh;
}
/* The block thumb: square, full track height, hard black right edge. */

.trs-11 input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 28px;
  height: 26px;
  border: 0;
  border-radius: 0;
  border-right: 3px solid var(--color-trs11-ink);
  background: var(--color-trs11-hot);
  cursor: ew-resize;
  transition: background .15s;
}

.trs-11 input[type="range"]:hover::-webkit-slider-thumb {
  background: oklch(0.62 0.22 27);
}

.trs-11 input[type="range"]::-moz-range-thumb {
  width: 28px;
  height: 26px;
  border: 0;
  border-radius: 0;
  background: var(--color-trs11-hot);
  cursor: ew-resize;
}

@media (prefers-reduced-motion: reduce) {
  .trs-11 input[type="range"]::-webkit-slider-thumb {
    transition: none;
  }
}
```

## JavaScript
```js
(function(){
  var root = document.getElementById('trs-11-root');
  var inp = document.getElementById('trs-11-inp');
  var num = document.getElementById('trs-11-num');
  var buttons = Array.prototype.slice.call(document.querySelectorAll('#trs-11-presets button'));

  function update(){
    var v = +inp.value;
    root.style.setProperty('--v', v / 100);
    num.textContent = v;
    buttons.forEach(function(b){ b.setAttribute('aria-pressed', String(+b.dataset.val === v)); });
  }
  inp.addEventListener('input', update);
  buttons.forEach(function(b){
    b.addEventListener('click', function(){ inp.value = b.dataset.val; update(); });
  });
  document.addEventListener('keydown', function(e){
    if (e.target.tagName === 'INPUT' && e.target !== inp) return;
    if (e.key >= '1' && e.key <= '9') { inp.value = +e.key * 10; update(); }
    else if (e.key === '0') { inp.value = 100; update(); }
  });
  update();
})();
```

How this works

Nothing is soft. The card has a 3px border and a 6px zero-blur shadow; the track is a bordered rectangle; the thumb (CSS) is a 28×32px red block with a black right edge, sized to the track height so it reads as a chunk of the bar rather than a knob on it.

Snapping is honest. step="4" plus transition-none on the fill means the value moves in visible increments — the mechanical feel is the design, not a limitation.

Keyboard shortcuts are the upgrade. The original suggested them; here digits jump to decades, arrows step, and the preset buttons mirror the state with aria-pressed.

Make it yours

  • Accent: --color-trs11-hot — chartreuse oklch(0.9 0.2 125) or electric blue read equally brutalist.
  • Track height: the track's h-8 and the thumb's height must change together or the chunk illusion breaks.
  • Step: step=&quot;4&quot; controls the mechanical granularity; step=&quot;1&quot; feels smooth and loses the effect.

Gotchas — read before shipping

  • The thumb height must equal the track's inner height exactly, or it overflows the border — they are declared within a line of each other for that reason.
  • Firefox rounds ::-moz-range-thumb unless border-radius: 0 is explicit. It is.
  • A 6px offset shadow needs 6px of room. The stage keeps padding on the bottom and right so the shadow is never clipped.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Square thumbs need the explicit border-radius: 0 Firefox rule shipped in the stylesheet; everything else is plain utilities.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Theme tokensset in @theme, used by a utility

HTML & JSno Tailwind involved

Search CodeFronts

Loading…