Interactive
Dual range slider
Two thumbs for a minimum and a maximum over two native range inputs, which keep the values for the form. Steps, a minimum gap, formatted tooltips and the WAI-ARIA slider keys. Needs monsoon.js.
Needs monsoon.js. The styles work on their own, and the behavior comes from the optional interactive layer: add <script src="https://cdn.jsdelivr.net/npm/monsooncss/dist/monsoon.js" defer></script> or import 'monsooncss/js'. See the interactive layer.
Example
<div class="grid gap-10 max-w-sm pt-8">
<div class="range-dual" data-m-range-dual data-m-range-dual-format="currency:USD" data-m-range-dual-gap="50">
<input type="range" class="range" name="min-price" min="0" max="1000" step="10" value="180" aria-label="Minimum price">
<input type="range" class="range" name="max-price" min="0" max="1000" step="10" value="720" aria-label="Maximum price">
</div>
<div class="range-dual" data-m-range-dual data-m-range-dual-format="percent" data-m-range-dual-tooltips="always">
<input type="range" class="range" min="0" max="100" value="25" aria-label="Lower bound">
<input type="range" class="range" min="0" max="100" value="60" aria-label="Upper bound">
</div>
</div>JavaScript API
Attribute
data-m-range-dual
Options
| Option | Description |
|---|---|
data-m-range-dual-format="currency:USD" (or percent, unit:kilometer) | |
data-m-range-dual-gap="50" | |
data-m-range-dual-tooltips="always" | |
min, max and step on the inputs |
Methods
| Method | Description |
|---|---|
Monsoon.rangeDual(el).value | |
Monsoon.rangeDual(el).value = [100, 400] |
Events
| Event | Description |
|---|---|
monsoon:change { min, max } | |
input and change on the native inputs |
Classes
6 classes. Click a name to copy it. Utilities on the same element always win over component defaults, so any of them can be adjusted with plain utility classes.
| Class | Type | What it does |
|---|---|---|
| Base | Base class of the dual range slider. On a <div> in the example. Sets grid display, gap, block display, height, margin and pointer cursor, and --tone, --tone-fg and --_thumb.CSS |
|
| Modifier | Modifier, combined with the range-dual class. Not used in the example above. Sets absolute position, offsets, height, transform, background and corner radius.CSS |
|
| Modifier | Modifier, combined with the range-dual class. Not used in the example above. Sets absolute position, offsets, width, background, corner radius and text color.CSS |
|
| Modifier | Modifier, combined with the range-dual class. Not used in the example above. Sets absolute position, offsets, stacking order, width, height and margin.CSS |
|
| Modifier | Modifier, combined with the range-dual class. Not used in the example above. Sets absolute position, offsets, padding, text size, font weight and text style.CSS |
|
| Part | Part of the dual range slider. On an <input> in the example. Sets border, not-allowed cursor, opacity, block display, width and height, and 8 custom properties.CSS |
Usage
The styles ship inside the same stylesheet as the utilities, and the behavior comes from the optional monsoon.js script, which enhances any element with a matching data-m attribute, including markup added later.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/monsooncss">
<script src="https://cdn.jsdelivr.net/npm/monsooncss/dist/monsoon.js" defer></script>
<!-- Dual range slider: start from the base class, then add modifiers -->
<div class="grid gap-10 max-w-sm pt-8">
<div class="range-dual" data-m-range-dual data-m-range-dual-format="currency:USD" data-m-range-dual-gap="50">
<input type="range" class="range" name="min-price" min="0" max="1000" step="10" value="180" aria-label="Minimum price">
<input type="range" class="range" name="max-price" min="0" max="1000" step="10" value="720" aria-label="Maximum price">
</div>
<div class="range-dual" data-m-range-dual data-m-range-dual-format="percent" data-m-range-dual-tooltips="always">
<input type="range" class="range" min="0" max="100" value="25" aria-label="Lower bound">
<input type="range" class="range" min="0" max="100" value="60" aria-label="Upper bound">
</div>
</div>Theme it with --seed on any ancestor, for example style="--seed: #0d9488", and force a scheme with class="dark" or class="light" on a wrapper.
Accessibility
- Give every control a visible
labellinked withfor, or anaria-labelwhen the purpose is obvious from context. Link help and error text witharia-describedby; invalid styles use:user-invalid, so they appear only after the user interacts. - Every interactive part shows a visible focus ring with
:focus-visible, and tone colors pair with-foregroundtokens that keep text at 4.5:1 or better in light and dark mode.