Skip to content

Slider Range

Provide an ordered value list in markup, or assign an array to the value property. Give each thumb a stable label through its thumb-label-{n} slot and format its spoken value with valueLabelHandler. Tab moves between the minimum and maximum thumbs, while the arrow keys adjust the focused thumb.

Minimum$80Maximum$320
Minimum price Maximum price

Code

The following example assumes that you have imported the component and set up the theme.

Price Range
<div class="price-range-example">
<div class="price-range-heading">
<label for="nightly-price">Nightly price</label>
<div class="price-range-values">
<span>
Minimum
<output data-minimum>$80</output>
</span>
<span>
Maximum
<output data-maximum>$320</output>
</span>
</div>
</div>
<sv-slider
id="nightly-price"
class="price-range"
aria-description="Filters stays by nightly price"
max="500"
step="10"
value="80 320"
>
<span slot="thumb-label-1">Minimum price</span>
<span slot="thumb-label-2">Maximum price</span>
</sv-slider>
</div>
<script type="module">
/** @type {HTMLElement} */
const example = document.querySelector(".price-range-example");
/** @type {Slider} */
const slider = example.querySelector(".price-range");
/** @type {HTMLOutputElement} */
const minimumOutput = example.querySelector("[data-minimum]");
/** @type {HTMLOutputElement} */
const maximumOutput = example.querySelector("[data-maximum]");
slider.valueLabelHandler = value => `$${value} per night`;
updateOutputs();
slider.addEventListener("valuechange", updateOutputs);
function updateOutputs() {
const values = slider.value;
if (!Array.isArray(values)) return;
const [minimum, maximum] = values;
minimumOutput.value = ` $${minimum}`;
maximumOutput.value = ` $${maximum}`;
}
</script>
33 collapsed lines
<style>
.price-range-example {
display: grid;
gap: 1.5rem;
max-inline-size: 36rem;
padding: clamp(1rem, 4vw, 2rem);
margin: auto;
background: var(--sv-gray-7);
border: 1px solid var(--sv-gray-5);
border-radius: var(--sv-bdr-rad-lg);
}
.price-range-heading,
.price-range-values {
display: flex;
flex-wrap: wrap;
gap: 0.75rem 1.5rem;
align-items: center;
justify-content: space-between;
}
.price-range-heading > label {
font-weight: 700;
}
.price-range-values {
font-size: 0.85rem;
color: var(--sv-gray-3);
output {
font-weight: 700;
color: var(--sv-gray-1);
}
}
.price-range {
--sv-thickness: 0.7rem;
--sv-thumb-size: 1.5rem;
inline-size: 100%;
&::part(track) {
background: var(--sv-gray-6);
}
&::part(fill) {
background: var(--sv-accent);
}
&::part(thumb) {
filter: drop-shadow(0 2px 3px rgb(0 0 0 / 25%));
}
}
</style>