KKUONIDesign System

Components

Range Slider

Beta

A draggable slider for selecting a numeric value within a defined range. Used for price filters, budget selectors, and rating range pickers.

4000
50010000

Purpose

The RangeSlider lets users select a value by dragging a thumb along a track — a more spatial and efficient interaction than typing in a number field when the user is exploring a range. Typical travel use cases:

  • Price filter — "Max budget: £4,000" on search results
  • Star rating filter — "3 stars and above"
  • Holiday duration — "Up to 14 nights"

The filled track portion is always Site Teal. The current value displays next to the label in teal. Min/max labels appear at each end of the track.

Usage

Reach for RangeSlider when the user is exploring a continuous range and dragging feels more natural than typing — a budget cap, a duration cutoff, a minimum star rating. When the user needs to enter or adjust a precise, specific number (like traveller count), use CounterInput or a plain Input instead.

RangeSlider typically appears in a search filter panel or sidebar, alongside other filter controls, rather than inside a booking form itself.

Anatomy

40
0100
  1. 1
    LabelDescriptive label on the left of the header row. 14px medium weight.
  2. 2
    Value displayCurrent formatted value on the right of the header row. Teal, semibold. Updates live as thumb moves.
  3. 3
    Track background6px tall pill track in grey-200. Full width of the container.
  4. 4
    Filled trackTeal portion of the track from left edge to thumb position. Updates with thumb.
  5. 5
    Thumb20×20px white circle with teal border and small shadow. Draggable handle.
  6. 6
    Range labelsMin value on the far left, max on the far right. 12px grey-400.

Variants

Default — numeric

10
328

With custom format

Use formatValue to display currency, units, or custom suffixes.

5000
50015000

Without value label

Set showValue={false} when displaying the value elsewhere (e.g. in a summary line).

15

Disabled

3000
010000

States

StateTrack fillThumb
DefaultTealWhite + teal border
Hover (thumb)TealElevated shadow
FocusTealTeal focus ring (2px, 2px offset)
DisabledGrey-300Opacity 60%, cursor-not-allowed

Best practices

Do

Always pair the slider with a label and formatted current value so the user knows exactly what they are adjusting.

'Maximum budget: £4,500' is unambiguous about what value is being set.

Don't

Render a RangeSlider without a label in a filter panel.

A slider without a label is impossible to interpret for sighted and screen reader users alike.

Do

Set step to a value that produces clean, meaningful stops (100 for currency, 1 for star ratings).

£100 steps snap to round numbers — more natural for price selection than £37 increments.

Don't

Use step=1 on wide price ranges where any specific value is acceptable to the user.

Step of 1 on a £0–15,000 price range creates 15,000 possible stops — too granular.

Do

Set defaultValue near the midpoint or to a sensible starting point for the typical user.

Starting at £3,000 on a 'Max budget' slider covers most Kuoni holidays and saves scrolling.

Don't

Always initialise at the minimum value on wide ranges.

Starting at the minimum forces all users to drag from £0 when most want a mid-range value.

Do

Use formatValue to show currency symbols, units, or suffixes alongside the raw number.

'£4,500' is clear. The inline teal label updates as the user drags.

Don't

Show raw numeric values without formatting on currency or star-rating sliders.

A raw '4500' with no context reads as a page count or quantity.

Props

PropTypeDefaultDescription
minnumber0Minimum value of the range. Shown at the left end of the track.
maxnumber100Maximum value. Shown at the right end of the track.
stepnumber1Increment between selectable values. Use 100 for currency, 1 for ratings.
valuenumberControlled current value. When set, parent must handle onChange to update it.
defaultValuenumbermidpointInitial value for uncontrolled usage. Defaults to midpoint between min and max.
onChange(value: number, event: Event) => voidCalled on every change as the thumb moves.
disabledbooleanfalseDisables dragging. Track turns grey, opacity 60%.
labelstringVisible label on the left of the header row. Associated via htmlFor.
showValuebooleantrueWhether to display the current formatted value on the right of the header.
formatValue(value: number) => stringv => String(v)Custom formatter for the displayed value and aria-valuetext. e.g. (v) => `£${v}`.
errorstringValidation error message shown below the track.
helpTextstringHelp text below the track. Hidden when error is set.
idstring'range-slider'ID for the native input element. Used by the label htmlFor.
classNamestringAdditional Tailwind classes on the root container.

Accessibility

Native input

RangeSlider renders a native <input type="range"> visually overlapping the custom track. The native element handles all keyboard and pointer interactions natively, ensuring compatibility with assistive technologies.

ARIA attributes

<input
  type="range"
  aria-valuemin={min}
  aria-valuemax={max}
  aria-valuenow={current}
  aria-valuetext={formatValue(current)}  // e.g. "£4,500"
/>

aria-valuetext is critical — without it, screen readers announce the raw number. With it, they announce the formatted string: "Maximum price per person, slider, £4,500".

Keyboard interaction

KeyAction
TabFocus the slider
Arrow Left / Arrow DownDecrease value by one step
Arrow Right / Arrow UpIncrease value by one step
HomeJump to minimum value
EndJump to maximum value
Page DownDecrease by 10% of range
Page UpIncrease by 10% of range

Focus ring

Focus ring appears on the thumb via focus-visible:ring-2 focus-visible:ring-teal focus-visible:ring-offset-2.

  • CounterInput — better suited to selecting a precise, specific number (e.g. traveller count) rather than exploring a continuous range.
  • Input — use when the user needs to type an exact numeric value directly rather than drag to an approximate one.