Skip to main content

Forms

Range

Use custom range inputs for consistent cross-browser styling and built-in customization.

View page source on GitHub

Overview#

Create custom <input type="range"> controls with .form-range. The track (the background) and thumb (the value) are both styled to appear the same across browsers.

<label for="range1" class="form-label">Example range</label>
<input type="range" class="form-range" id="range1">

In the felt look, the track is a groove pressed into the felt and the thumb is a small primary felt patch with a cast shadow.

Filled track#

Unlike Bootstrap, felt-css can fill the track from the left up to the thumb. CSS can't read an input's value, so the filled part comes from the --fill custom property (default 0%, i.e. no fill). Set it inline for a static value:

<label for="rangeFill" class="form-label">Volume</label>
<input type="range" class="form-range" id="rangeFill" value="70" style="--fill: 70%">

To follow the thumb while it's dragged, update --fill from JavaScript. This works for any min, max and step:

for (const range of document.querySelectorAll('.form-range')) {
  const update = () => {
    const min = +range.min || 0
    const max = range.max === '' ? 100 : +range.max
    range.style.setProperty('--fill', `${(range.value - min) / (max - min) * 100}%`)
  }
  range.addEventListener('input', update)
  update()
}

The ranges below this point on this page use exactly that script.

Disabled#

Add the disabled boolean attribute on an input to give it a grayed out appearance, remove pointer events, and prevent focusing.

<label for="disabledRange" class="form-label">Disabled range</label>
<input type="range" class="form-range" id="disabledRange" disabled>

Min and max#

Range inputs have implicit values for min and max—0 and 100, respectively. You may specify new values for those using the min and max attributes.

<label for="range2" class="form-label">Example range</label>
<input type="range" class="form-range" min="0" max="5" id="range2">

Steps#

By default, range inputs "snap" to integer values. To change this, you can specify a step value. In the example below, we double the number of steps by using step="0.5".

<label for="range3" class="form-label">Example range</label>
<input type="range" class="form-range" min="0" max="5" step="0.5" id="range3">

Output value#

The value of the range input can be shown using the output element and a bit of JavaScript.

<label for="range4" class="form-label">Example range</label>
<input type="range" class="form-range" min="0" max="100" value="50" id="range4">
<output for="range4" id="rangeValue" aria-hidden="true"></output>
const rangeInput = document.getElementById('range4')
const rangeOutput = document.getElementById('rangeValue')

rangeOutput.textContent = rangeInput.value
rangeInput.addEventListener('input', () => {
  rangeOutput.textContent = rangeInput.value
})