Range slider
A slider for a form, written as one native input type="range": a budget, a quantity, a bracket between two values.
Documentation
-
Copy to Webflow
Add Geist and Geist Mono to your site's fonts (Site settings, Fonts, Google Fonts) before pasting: Webflow removes any font your site has not installed. -
Add custom CSS
Custom CSS in WebflowThis CSS already ships inside the Webflow embed, so a pasted section needs nothing added. Paste it yourself, in the page or the site custom code, only if the effect runs on several pages. The tutorial explains where.
See the tutorialThe look of the preview is therange-slider-*classes of the paste; the size of a figure is the font size of the box markeddata-range-slider-output. The Embed draws the scale, the needle and the figure, and reads three variables with a fallback,--range-slider-ink(the needle and the marks it has passed),--range-slider-rest(the other marks) and--range-slider-quiet(the labels and the unit): set them on the form, or on anything above it, in a rule of your own. The head of the needle is the settingcolor. The track is 70px tall and as wide as the box the field is in. The labels of the scale are set in Geist Mono by the classrange-slider-label, which the engine writes: give that class anotherfont-familyin a rule of your own to change it. -
Add custom JS
Custom JavaScript in WebflowThis script already ships inside the Webflow embed, settings block included. You paste it yourself, before the closing body tag of the page or the site custom code, only when the effect has to run on several pages, and the tutorial says how to choose.
See the tutorial -
Use it on your own elements
How to add a custom attribute in WebflowA custom attribute is a pair, a name and a value, typed in the Settings panel of the element you selected, under Custom attributes. The name is what the script looks for, the value is what it reads. The tutorial shows the panel.
See the tutorialCustom attributesSelect the element on the canvas and open the Settings panel. Under Custom attributes, add a pair: the name on the left, the value on the right.Custom attribute What it does data-range-slider Marks the input that becomes a slider. It takes no value: leave the value field empty. The settings below go on the same element, or on the box of a pair for both of its inputs. data-range-slider-min, data-range-slider-max, data-range-slider-step, data-range-slider-value On the input, in Webflow: the two ends of the scale, the size of a step and the first value, as numbers. A Webflow field has no setting for them. In plain HTML they are the input's own min, max, step and value, and these four are not needed. Without them the scale runs from 0 to 100 by steps of 1. [ Required ] data-range-slider-output On the box that shows the value. It takes no value when the box and the input are children of the same element; or the id of its input when the box is anywhere else on the page. Its text is what shows before the script, and on the Designer canvas. Without it the slider works and nothing writes the value. [ Optional ] data-range-slider-pair On a box that holds two marked inputs, the lower one first: they share one scale and cannot cross. It takes no value, and carries the settings for both. The first box marked data-range-slider-output in its parent shows the lower value, the second the upper one. [ Optional ] data-range-slider-field On a box around an input and the box of its value, when the two are not children of the same element. It takes no value. [ Optional ] data-range-slider-submit On the Link block that stands in for the send button of the form, as in the paste. It takes no value. The engine makes it send the form it is in. A native submit button needs nothing. [ Optional ] data-range-slider-ready Written by the engine on a mounted input or pair. The track it adds carries data-range-slider-track, with data-range-slider-held while a needle is held; a needle carries data-range-slider-held and data-range-slider-focus, a mark the needle has passed data-range-slider-on. Never written by hand; the stylesheet reads them, and so can a rule of yours. [ Optional ] SettingsEvery setting is a custom attribute too, added the same way and on the same element. An attribute always wins over the defaults written in the code.Attribute Default What it is data-range-slider-color #ffab1a The colour of the head of the needle. Options: any CSS colour. The stem, the marks and the focus ring are the ink, --range-slider-ink. data-range-slider-currency empty The currency the value is written in, as a three letter code. Options: USD, EUR, GBP, any ISO 4217 code; empty for a value that is not money. The sign is placed where the language puts it, $12,500 in English, 12 500 € in French. data-range-slider-unit empty The unit written after the value, when it is not money. Options: a unit the browser knows, in English and in the singular, percent, kilometer, kilogram, hour, written short and in the language of the page (50%, 12 km); or any word of yours, reams, gsm; or two words parted by a vertical bar, the singular then the plural (week, then weeks), the first for one and the second for several. data-range-slider-locale empty The language the figures are written in. Options: empty, the language of the page, read from the nearest lang attribute, then from the browser; or a tag, fr, de-CH, en-GB. data-range-slider-ticks empty The values of the scale that carry a label. Options: empty, the two ends; or a list of values, 500, 25000, 50000. A label that would run into its neighbour on a narrow screen is left out. data-range-slider-gap 1 In a pair, the least distance the two needles keep, counted in steps. data-range-slider-lean 12 How far the needle leans when it is pulled fast, in degrees. data-range-slider-roll 0.5 The time a column of the figure takes to turn, in seconds.
Two files, no build step.
It runs in the browser only. Load it with a script tag in plain HTML, in a
client-side script in Astro, never in the frontmatter. In React, call
RangeSlider.mount(ref.current) in useEffect and
destroy() in its cleanup.
-
Tune it, either way
Per element with an attribute, or once for the whole site by editingDEFAULTSat the top of the file.Attribute Default What it is Lower Higher data-range-slider-color #ffab1a The colour of the head of the needle. Options: any CSS colour. The stem, the marks and the focus ring are the ink, --range-slider-ink. data-range-slider-currency empty The currency the value is written in, as a three letter code. Options: USD, EUR, GBP, any ISO 4217 code; empty for a value that is not money. The sign is placed where the language puts it, $12,500 in English, 12 500 € in French. data-range-slider-unit empty The unit written after the value, when it is not money. Options: a unit the browser knows, in English and in the singular, percent, kilometer, kilogram, hour, written short and in the language of the page (50%, 12 km); or any word of yours, reams, gsm; or two words parted by a vertical bar, the singular then the plural (week, then weeks), the first for one and the second for several. data-range-slider-locale empty The language the figures are written in. Options: empty, the language of the page, read from the nearest lang attribute, then from the browser; or a tag, fr, de-CH, en-GB. data-range-slider-ticks empty The values of the scale that carry a label. Options: empty, the two ends; or a list of values, 500, 25000, 50000. A label that would run into its neighbour on a narrow screen is left out. data-range-slider-gap 1 In a pair, the least distance the two needles keep, counted in steps. 0 lets the two values meet Keeps a wider bracket, 5 for five steps at least data-range-slider-lean 12 How far the needle leans when it is pulled fast, in degrees. Stiffer; 0 and it stays upright Looser, more shown; over 18 it starts to wave data-range-slider-roll 0.5 The time a column of the figure takes to turn, in seconds. Snappier; 0 and the figure changes at once Slower and more shown; over 0.8 the figure is late on the needle -
Drive it from JavaScript
When a script reads the value as it moves, sets it, or adds sliders after the page has loaded.const element = document.querySelector('[data-range-slider]'); element.addEventListener('range-slider:change', (e) => { console.log(e.detail); }); // Follow the value: a price that is computed, a summary that updates. element.addEventListener('range-slider:change', (event) => { console.log(event.detail.value, event.detail.text); // 12500, '12,500 US dollars' }); const slider = RangeSlider.mount(element); // the input auto() mounted, or a new one slider.set(30000); // the needle travels, the figure turns slider.set(30000, true); // at once slider.value(); // 30000, or [80, 120] for a pair // When the form leaves the page: slider.destroy(); // the input is back where it was, a plain range input
-
Fit it to your page
The stylesheet goes in the head and the script before the end of the body; the markup of one slider is three elements:
html <label for="budget">Monthly budget</label> <div data-range-slider-output>$12,500</div> <input id="budget" name="budget" type="range" min="500" max="50000" step="500" value="12500" data-range-slider data-range-slider-currency="USD">The text of the box marked
data-range-slider-outputis what shows without the script; with it, the engine writes the figure there. The size of the figure is the font size of that box: a headline size for one slider, a text size for a row of them.A pair, for a bracket:
html <div role="group" aria-label="Paper weight" data-range-slider-pair data-range-slider-unit="gsm"> <input type="range" name="from" min="60" max="300" step="10" value="80" aria-label="Lightest" data-range-slider> <input type="range" name="to" min="60" max="300" step="10" value="120" aria-label="Heaviest" data-range-slider> </div>The first box marked
data-range-slider-outputin the parent of the pair shows the lower value, the second the upper one.The labelled values can also come from a
<datalist>named by thelistattribute of the input, the HTML way; thelabelof an option is then the text under its mark.The page hears a change the way it hears any input:
inputwhile the value moves,changewhen it is let go.range-slider:changesays the same with the value as a number and as words.js const slider = RangeSlider.mount(document.querySelector('#budget')); slider.set(30000); // the needle travels, the figure turns slider.set(30000, true); // at once slider.value(); // 30000, or [80, 120] for a pair -
Avoid the pitfalls
- Name each input. The slider is a form field like any other: without a
namethe form does not send it. In a pair, each input has its own name and its ownaria-label, and the box carriesrole="group"and a name. - The value box holds text only. The engine replaces what is in it and puts it back on
destroy(). Do not put the label of the field inside it. - **
min,maxandstepare read once.** After changing them from a script,destroy()thenmount(). A value written from a script,input.value = 20000, is picked up byrefresh(), or useset(). - The track is 70px tall, 44 for the scale and the rest for its labels. It is as wide as the parent of the input: give that parent a width.
- Colours are custom properties read with a fallback: set
--range-slider-ink,--range-slider-restand--range-slider-quieton the field or on the page for a dark ground. The head of the needle is the settingcolor. - Webflow has no range field. The paste carries a number field marked
data-range-slider, with the scale indata-range-slider-min,-max,-stepand-value; the engine turns it into a range input when the page loads. On the canvas, which runs no Embed, it shows as a plain field. - A unit in the plural:
unittakesweek|weeksfor a word of yours; the units the browser knows are written short,wk, which is rarely wanted in a headline.
- Name each input. The slider is a form field like any other: without a
One click on Copy the AI prompt copies everything an assistant needs to build this effect: the complete code, the markup, the dependency, every setting and every pitfall.
What it does
Range slider is an animated form for Webflow and vanilla JavaScript, with no library. Also called custom range slider, dual range slider or price range slider.
A slider for a form, written as one native input type="range": a budget, a quantity, a bracket between two values. The engine reads what the input already says, min, max, step and value, and draws a graduated scale in its place, with a needle whose foot stays on the value while its head trails behind the hand and stands back up when it stops. The marks the needle has passed take the ink, the others stay pale: no bar fills. Beside it the value is written large, in the language of the page, with its currency or its unit, and each column of the figure turns on its own, up when the value grows, down when it shrinks; run through fast, a column stops turning and shows each digit whole, so the figure is never a blur. On a scale of few steps each step is a notch the needle holds on to. Two inputs in one box make a pair that shares a scale and cannot cross. The input stays the control: it is what the form sends, what the keyboard moves (arrows, Page Up and Page Down, Home and End) and what a screen reader reads, with aria-valuetext saying the value and its unit in words. A finger moving up or down on the scale scrolls the page. Without JavaScript the input is the slider of the browser. Reduced motion respected. No library. Pattern type range slider, range input, price range, budget slider.
Updated
Questions
Webflow has no range field, so the slider is a text field of type Number with the custom attribute data-range-slider, and its scale in data-range-slider-min, data-range-slider-max, data-range-slider-step and data-range-slider-value. The Embed turns it into a range input when the page loads; the paste already carries all of it inside a native Form block, and the form sends the number under the name of the field.
Put a text block marked data-range-slider-output beside the input: the engine writes the value in it. data-range-slider-currency="USD" formats it as money and data-range-slider-unit="percent" or a word of yours as a unit, in the language of the page, through Intl.NumberFormat. The size of the figure is the font size of that block.
Yes. Put two inputs marked data-range-slider in a box marked data-range-slider-pair, the lower one first: they share one scale and cannot cross, and data-range-slider-gap sets the least distance they keep, in steps. Each one is a field of its own in the form, with its own name.
Yes, because the control is still the native input type="range". The arrow keys move it by one step, Page Up and Page Down by a tenth of the scale, Home and End go to the ends, and aria-valuetext says the value with its unit in words, "12,500 US dollars". Without JavaScript the browser's own slider is shown.
No to both. The track sets touch-action: pan-y, so a finger moving up or down scrolls the page and only a sideways move pulls the needle; a tap sends it there. The engine is one script with no dependency, three springs on one requestAnimationFrame clock that sleeps at rest.