|$ curl https://forge-ai.dev/api/markdown?path=docs/components/sliders
$cat docs/sliders-&-range-inputs.md
updated Recently·14 min read·published

Sliders & Range Inputs

CSSHTMLUIIntermediate🎯Free Tools

Range inputs for selecting values within a continuum — from simple volume sliders to multi-handle price range pickers with custom styling and step increments.

Basic Range Slider

A minimal range input with a live value readout. The native <input type="range"> element provides built-in drag interaction, keyboard support, and screen reader accessibility out of the box. Use min, max, and value attributes to set the range boundaries and initial position.

basic-slider
Live
untitled.html
HTML
1<div class="slider-demo">
2 <div class="slider-group">
3 <label class="slider-label">
4 Volume
5 <span class="slider-value" id="vol-val">
6 50
7 </span>
8 </label>
9 <input type="range" class="slider" id="vol-slider" min="0" max="100" value="50"/>
10 </div>
11</div>
preview
Custom Styled

Custom thumb and track styling using ::-webkit-slider-thumb and ::-webkit-slider-runnable-track pseudo-elements. Includes a gradient-filled track that reflects the current value via a sibling div overlay technique. The range input sits on top with a transparent background.

custom-styled
Live
untitled.html
HTML
1<div class="styled-demo">
2 <div class="field">
3 <label>
4 Brightness
5 </label>
6 <div class="track-wrap">
7 <input type="range" class="styled-slider" id="bright" min="0" max="100" value="65"/>
8 <div class="track-fill" id="bright-fill" style="width:65%">
9 </div>
10 </div>
11 <div class="field-info">
12 <span class="fi-icon">
13
14 </span>
15 <span class="fi-val" id="bright-val">
16 65%
17 </span>
18 </div>
19 </div>
20 <div class="field">
21 <label>
22 Contrast
23 </label>
24 <div class="track-wrap">
25 <input type="range" class="styled-slider" id="contrast" min="0" max="100" value="40"/>
26 <div class="track-fill" id="contrast-fill" style="width:40%">
27 </div>
28 </div>
29 <div class="field-info">
30 <span class="fi-icon">
31
32 </span>
33 <span class="fi-val" id="contrast-val">
34 40%
35 </span>
36 </div>
37 </div>
38 <div class="field">
39 <label>
40 Saturation
41 </label>
42 <div class="track-wrap">
43 <input type="range" class="styled-slider" id="sat" min="0" max="100" value="80"/>
44 <div class="track-fill" id="sat-fill" style="width:80%">
45 </div>
46 </div>
47 <div class="field-info">
48 <span class="fi-icon">
49
50 </span>
51 <span class="fi-val" id="sat-val">
52 80%
53 </span>
54 </div>
55 </div>
56</div>
preview
CSS Pseudo-Elements Reference

The range input exposes several pseudo-elements for styling. WebKit and Mozilla use different naming conventions, so you need to target both to ensure cross-browser compatibility.

slider-pseudo-elements.css
CSS
1/* WebKit (Chrome, Safari, Edge) */
2input[type="range"]::-webkit-slider-runnable-track {
3 height: 6px;
4 background: #2A2A3E;
5 border-radius: 3px;
6}
7
8input[type="range"]::-webkit-slider-thumb {
9 appearance: none;
10 width: 18px;
11 height: 18px;
12 border-radius: 50%;
13 background: #00FF41;
14 margin-top: -6px; /* center on track */
15}
16
17/* Mozilla (Firefox) */
18input[type="range"]::-moz-range-track {
19 height: 6px;
20 background: #2A2A3E;
21 border-radius: 3px;
22}
23
24input[type="range"]::-moz-range-thumb {
25 width: 18px;
26 height: 18px;
27 border-radius: 50%;
28 background: #00FF41;
29 border: none;
30}
Price Range (Dual Handle)

A dual-handle range slider for selecting a price range. Two overlapping range inputs create the min/max handles, with the track highlight between them. Both inputs share the same track but have pointer-events: none on the input with pointer-events: all only on the thumb.

price-range
Live
untitled.html
HTML
1<div class="range-demo">
2 <div class="range-header">
3 <span class="range-title">
4 Price Range
5 </span>
6 <span class="range-display">
7 $
8 <span id="min-disp">
9 25
10 </span>
11 — $
12 <span id="max-disp">
13 75
14 </span>
15 </span>
16 </div>
17 <div class="range-track">
18 <div class="range-fill" id="range-fill">
19 </div>
20 <input type="range" class="range-input" id="range-min" min="0" max="100" value="25"/>
21 <input type="range" class="range-input" id="range-max" min="0" max="100" value="75"/>
22 </div>
23 <div class="range-labels">
24 <span>
25 $0
26 </span>
27 <span>
28 $50
29 </span>
30 <span>
31 $100
32 </span>
33 </div>
34</div>
preview
Step Slider

A slider with discrete step increments and labeled tick marks. The step attribute constrains values to specific intervals, and custom tick marks show each possible position. The track fill updates dynamically to show the selected range.

step-slider
Live
untitled.html
HTML
1<div class="step-demo">
2 <div class="step-header">
3 <span class="step-title">
4 Zoom Level
5 </span>
6 <span class="step-val" id="step-val">
7 2x
8 </span>
9 </div>
10 <div class="step-track">
11 <input type="range" class="step-slider" id="step-slider" min="0" max="4" step="1" value="2"/>
12 <div class="step-ticks">
13 <span class="tick">
14 </span>
15 <span class="tick">
16 </span>
17 <span class="tick active">
18 </span>
19 <span class="tick">
20 </span>
21 <span class="tick">
22 </span>
23 </div>
24 <div class="step-labels">
25 <span>
26 0.5x
27 </span>
28 <span>
29 1x
30 </span>
31 <span>
32 2x
33 </span>
34 <span>
35 4x
36 </span>
37 <span>
38 8x
39 </span>
40 </div>
41 </div>
42</div>
preview
Vertical Slider

Vertical sliders using CSS writing-mode: vertical-lr and direction: rtl for volume-mixer-style layouts. Each channel displays its value above and label below, creating a familiar audio mixing interface.

vertical
Live
untitled.html
HTML
1<div class="vert-demo">
2 <div class="vert-group">
3 <input type="range" class="vert-slider" orient="vertical" min="0" max="100" value="30"/>
4 <span class="vert-val" id="v1">
5 30
6 </span>
7 <span class="vert-ch">
8 CH 1
9 </span>
10 </div>
11 <div class="vert-group">
12 <input type="range" class="vert-slider" orient="vertical" min="0" max="100" value="65"/>
13 <span class="vert-val" id="v2">
14 65
15 </span>
16 <span class="vert-ch">
17 CH 2
18 </span>
19 </div>
20 <div class="vert-group">
21 <input type="range" class="vert-slider" orient="vertical" min="0" max="100" value="80"/>
22 <span class="vert-val" id="v3">
23 80
24 </span>
25 <span class="vert-ch">
26 CH 3
27 </span>
28 </div>
29 <div class="vert-group">
30 <input type="range" class="vert-slider" orient="vertical" min="0" max="100" value="45"/>
31 <span class="vert-val" id="v4">
32 45
33 </span>
34 <span class="vert-ch">
35 CH 4
36 </span>
37 </div>
38 <div class="vert-group">
39 <input type="range" class="vert-slider" orient="vertical" min="0" max="100" value="90"/>
40 <span class="vert-val" id="v5">
41 90
42 </span>
43 <span class="vert-ch">
44 CH 5
45 </span>
46 </div>
47</div>
preview
Labeled Sections

A slider with named zones that highlight as the handle passes through them \u2014 useful for settings that have named tiers or thresholds like quality presets. Each segment fills in sequence as the value increases.

labeled-zones
Live
untitled.html
HTML
1<div class="zone-demo">
2 <div class="zone-header">
3 <span class="zone-title">
4 Quality Preset
5 </span>
6 <span class="zone-name" id="zone-name">
7 Balanced
8 </span>
9 </div>
10 <div class="zone-track">
11 <div class="zone-fill" id="zone-fill">
12 </div>
13 <input type="range" class="zone-slider" id="zone-slider" min="0" max="4" step="1" value="2"/>
14 <div class="zone-segments">
15 <span class="seg" data-zone="Ultra Fast">
16 </span>
17 <span class="seg" data-zone="Fast">
18 </span>
19 <span class="seg active" data-zone="Balanced">
20 </span>
21 <span class="seg" data-zone="Quality">
22 </span>
23 <span class="seg" data-zone="Ultra">
24 </span>
25 </div>
26 </div>
27 <div class="zone-labels">
28 <span>
29 Ultra Fast
30 </span>
31 <span>
32 Fast
33 </span>
34 <span>
35 Balanced
36 </span>
37 <span>
38 Quality
39 </span>
40 <span>
41 Ultra
42 </span>
43 </div>
44</div>
preview
Disabled & Readonly

Sliders in disabled and read-only states. The disabled state prevents all interaction and dims the control with reduced opacity, while readonly preserves the value but blocks user changes. Both states use cursor: not-allowed to signal non-interactivity.

disabled-states
Live
untitled.html
HTML
1<div class="disabled-demo">
2 <div class="d-field">
3 <label>
4 Active Slider
5 </label>
6 <input type="range" class="d-slider" min="0" max="100" value="60"/>
7 <span class="d-val">
8 60
9 </span>
10 </div>
11 <div class="d-field">
12 <label>
13 Disabled Slider
14 </label>
15 <input type="range" class="d-slider disabled" min="0" max="100" value="40" disabled/>
16 <span class="d-val dim">
17 40
18 </span>
19 </div>
20 <div class="d-field">
21 <label>
22 Readonly Slider
23 </label>
24 <input type="range" class="d-slider readonly" min="0" max="100" value="75" readonly/>
25 <span class="d-val">
26 75
27 </span>
28 </div>
29</div>
preview
Slider with Tooltip

A slider with a floating tooltip that follows the thumb and displays the current value. The tooltip uses CSS transform: translateX() to position itself precisely above the thumb, and appears on hover and while dragging.

slider-tooltip
Live
untitled.html
HTML
1<div class="tip-demo">
2 <div class="tip-group">
3 <div class="tip-wrap">
4 <div class="tip-bubble" id="tip-bubble">
5 50
6 </div>
7 <input type="range" class="tip-slider" id="tip-slider" min="0" max="100" value="50"/>
8 </div>
9 <div class="tip-labels">
10 <span>
11 0
12 </span>
13 <span>
14 100
15 </span>
16 </div>
17 </div>
18</div>
preview
HTML Structure

The range input follows a semantic pattern: a <label> connected via for, the <input type="range"> with min/max/step/value attributes, and an aria live region for the current value. Always include the ARIA attributes for screen reader support.

slider-structure.html
HTML
1<label for="volume">Volume</label>
2
3<input type="range"
4 id="volume"
5 min="0" max="100"
6 value="50" step="1"
7 aria-valuenow="50"
8 aria-valuemin="0"
9 aria-valuemax="100" />
10
11<span aria-live="polite">50</span>
Best Practices

info

Always pair a range input with a visible value display. Users need precise feedback \u2014 the slider thumb alone is not enough to communicate the exact value. A tooltip or numeric readout works best.

warning

Custom-styled sliders require separate pseudo-element rules for -webkit- and -moz- prefixes. Test on both Chrome and Firefox to ensure consistent appearance across browsers.

best practice

Use the step attribute for discrete values (e.g., quality presets, zoom levels). For continuous values like volume or brightness, omit step or set it to 1 for smooth movement.
  • Always include aria-valuemin, aria-valuemax, and aria-valuenow for screen readers. The browser updates aria-valuenow automatically, but custom displays need manual updates.
  • Use aria-live="polite" on the value display so assistive technologies announce changes without interrupting the current task.
  • Minimum touch target for slider thumbs should be 44\u00d744px on mobile \u2014 increase thumb size or add invisible padding to meet WCAG touch target requirements.
  • For dual-handle range sliders, ensure handles cannot cross each other to maintain logical min/max ordering. Clamp values on the input event.
  • Consider providing a number input alongside the slider for users who need precise values. Sync both inputs bidirectionally.
  • Use font-variant-numeric: tabular-nums on value displays to prevent layout shifts as digits change width.