Skip to content

Dual Range Price Slider

Tailwind CSS min/max price slider with two handles, synced number inputs and a live histogram that counts products in the selected range.

Live preview

Open in new tab

Code

A dual range price slider built with Tailwind CSS and vanilla JavaScript: two handles on one track, linked number inputs for exact amounts and a small histogram that shows how many products fall inside the chosen range. It is a typical filter for online shops, real estate listings, job boards and any search page with a minimum and maximum value.

How it works

The root is .tdr-range, which carries the settings data-tdr-currency="$" and data-tdr-gap="50". Inside the card, data-tdr-histogram holds twenty .tdr-bar elements, each with a data-count. The .tdr-slider stacks a grey base track, the gradient .tdr-fill and two native input type="range" elements (.tdr-input) marked data-tdr-thumb="min" and data-tdr-thumb="max". Below them are two number fields (data-tdr-field="min" and "max"), a product count (data-tdr-count), a Reset button (data-tdr-reset), a Show results button (data-tdr-apply) and a role="status" line (data-tdr-live).

style.css removes the native look of both ranges, makes the inputs ignore pointer events while their thumbs accept them, and draws round thumbs with ::-webkit-slider-thumb and ::-moz-range-thumb. The fill uses left: var(--tdr-from) and right: calc(100% - var(--tdr-to)).

On DOMContentLoaded the script initializes every .tdr-range, sets each bar height from its data-count and listens for input on both ranges. It keeps the handles at least data-tdr-gap apart, puts the dragged handle on top with data-front, updates --tdr-from and --tdr-to, marks bars inside the range with data-in and adds up their counts. Typing in a number field and pressing Enter or leaving it rounds the value to the step, clamps it and moves the handle.

Customization

  • min, max, step and value on both range inputs (and the number fields): set your own scale, for example 0 to 5000 in steps of 100.
  • data-tdr-gap on .tdr-range: the minimum distance between the two handles; use 0 to let them meet.
  • data-tdr-currency on .tdr-range: use €, £ or an empty value for non-price ranges.
  • --tdr-accent and --tdr-accent-2 in style.css: change the handle border, the fill gradient and the active bars.
  • --tdr-thumb in style.css: make the handles larger for touch-heavy layouts.
  • data-count on each .tdr-bar: feed real counts from your catalog; remove data-tdr-histogram entirely if you do not need it.
  • Replace the simulated handler on data-tdr-apply in script.js with a fetch() call or a URL update that reloads your results.

Accessibility

Both handles are native range inputs, so arrow keys, Page Up, Page Down, Home and End work out of the box. Each has an aria-label ("Minimum price", "Maximum price") and an aria-valuetext such as "$650" set by the script. The number fields have visible labels, and the result is announced through the role="status" line after a handle is released, not on every step. The histogram is decorative and hidden with aria-hidden. Focused handles get a soft ring, and transitions are disabled under prefers-reduced-motion.

Usage notes

For several sliders on one page, repeat the .tdr-range block and give the number fields unique id values.

Requirements

Add these to your page (already included in the download):

  • <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

The Tailwind browser build is for prototyping. In production, compile Tailwind with its CLI or your bundler.

Dual Range Price Slider – Tailwind CSS range sliders component screenshot
Dual Range Price Slider · Tailwind CSS Range Sliders