Component Library

← Back to gallery

Range slider

Category: Forms · Tags: range, slider, output, price, filter

$250

How to use it

Use when an approximate value on a continuous scale is good enough and seeing it change helps, such as a maximum price filter or volume. When people need an exact number, give them a number input (or add one beside the slider). Change min, max, step, the currency formatting in the script, and the ids that tie the label and output to the input.

Accessibility

A native type="range" input with a <label for>, so it is announced as a slider and moved with the arrow keys, Page Up/Page Down and Home/End without any custom script. The current value is shown in an <output for> next to the label, and the script mirrors it into aria-valuetext ("$250") so screen readers announce the formatted price instead of a bare number; the minimum and maximum are printed under the track. The thumb is drawn by the browser with accent-color and the input shows a 2px focus outline. Text is #0f172a on #ffffff (17.85:1), the output #1e3a8a on #dbeafe (8.49:1) and the range ends #475569 on #ffffff (7.58:1).

Source (copy-ready)

<div class="dcl-range">
  <div class="dcl-range__top">
    <label class="dcl-range__label" for="dcl-range-price">Maximum price</label>
    <output class="dcl-range__output" for="dcl-range-price" id="dcl-range-output">$250</output>
  </div>
  <input class="dcl-range__input" id="dcl-range-price" name="max-price" type="range" min="0" max="500" step="10" value="250" aria-valuetext="$250">
  <div class="dcl-range__ends" aria-hidden="true">
    <span class="dcl-range__end">$0</span>
    <span class="dcl-range__end">$500</span>
  </div>
</div>
<style>
.dcl-range { max-width: 24rem; font: inherit; color: #0f172a; background-color: #ffffff; }
.dcl-range__top { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 0.5rem; }
.dcl-range__label { font-weight: 600; color: #0f172a; background-color: #ffffff; }
.dcl-range__output { padding: 0.1rem 0.5rem; border-radius: 0.375rem; font-weight: 700; font-variant-numeric: tabular-nums; color: #1e3a8a; background-color: #dbeafe; }
.dcl-range__input { display: block; width: 100%; max-width: 100%; margin: 0.75rem 0 0.25rem; accent-color: #1d4ed8; }
.dcl-range__input:focus-visible { outline: 2px solid #0f172a; outline-offset: 4px; }
.dcl-range__ends { display: flex; justify-content: space-between; font-size: 0.85rem; }
.dcl-range__end { color: #475569; background-color: #ffffff; }
</style>
<script>
(function () {
  document.querySelectorAll(".dcl-range").forEach(function (root) {
    if (root.dataset.dclBound) { return; }
    root.dataset.dclBound = "true";
    var input = root.querySelector(".dcl-range__input");
    var output = root.querySelector(".dcl-range__output");
    if (!input) { return; }
    function update() {
      var text = "$" + input.value;
      input.setAttribute("aria-valuetext", text);
      if (output) { output.textContent = text; }
    }
    input.addEventListener("input", update);
    update();
  });
})();
</script>

Was this useful? Send feedback.