1. Slider Anatomy
Track, progress fill, thumb, value label, and helper text
Track, progress fill, thumb, value label, and helper text
Guidelines for predictable slider UX
Try single, dual, and stepped sliders with live values
Handles are constrained so minimum cannot exceed maximum.
Useful for coarse controls where precision is unnecessary.
Keyboard and screen reader behavior
| Input | Behavior |
|---|---|
| Arrow Left/Right | Decrease / increase by step |
| Home | Jump to minimum |
| End | Jump to maximum |
| Page Up/Down | Larger jumps (browser dependent) |
| Screen reader | Announces role, current value, min, max |
Shared utility to paint progress and sync labels
function paint(slider) {
const min = Number(slider.min || 0);
const max = Number(slider.max || 100);
const val = Number(slider.value);
const pct = ((val - min) / (max - min)) * 100;
slider.style.setProperty('--pct', pct + '%');
}
function bind(slider, out, fmt) {
const sync = () => {
paint(slider);
out.textContent = fmt(slider.value);
};
slider.addEventListener('input', sync);
slider.addEventListener('change', sync);
sync();
}
Drop-in HTML + CSS + JS starter for branded sliders
<label class="slider-label" for="s1">Volume</label>
<input id="s1" class="slider-control" type="range" min="0" max="100" value="40" />
<span id="s1Out" class="slider-value">40%</span>
<style>
.slider-control {
--pct: 40%;
appearance: none;
width: 100%;
height: 8px;
border-radius: 999px;
background: linear-gradient(to right, var(--brand) 0 var(--pct), #d7deea var(--pct) 100%);
}
.slider-control::-webkit-slider-thumb {
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--brand);
border: 2px solid #fff;
}
</style>
<script>
const s1 = document.getElementById('s1');
const o1 = document.getElementById('s1Out');
const sync = () => {
const p = (Number(s1.value) / Number(s1.max)) * 100;
s1.style.setProperty('--pct', p + '%');
o1.textContent = s1.value + '%';
};
s1.addEventListener('input', sync);
sync();
</script>