data-range

Cross-browser styled range slider with optional value bubble, prefix/suffix formatting, and tick markers. Covers data-range, data-bubble, and data-markers.

Overview

The data-range attribute enhances a native <input type="range"> with cross-browser styling, an optional value bubble, prefix/suffix formatting, and tick markers. This is a combined page covering data-range, data-bubble, and data-markers.

<label for="volume">Volume</label> <input type="range" id="volume" data-range min="0" max="100" value="50">

How It Works

Add data-range to any <input type="range">. The init script:

  1. Wraps the input in a .range-wrapper div for layout control
  2. Normalizes cross-browser track and thumb styling via appearance: none
  3. Sets a --range-pct CSS custom property (0–100%) on every input event
  4. If data-bubble is present, creates an <output> element positioned above the thumb
  5. If data-markers is present, renders tick marks along the track based on the step attribute
  6. If a <datalist> is linked via list, renders labeled tick marks from the option elements

The underlying input remains a real form control. It submits with the form and fires native input and change events.

Attributes

Attribute Type Description
data-range boolean Enables cross-browser range styling and the --range-pct custom property.
data-bubble boolean Shows a floating value bubble above the thumb that updates on input.
data-prefix string Text prepended to the bubble value (e.g., "$").
data-suffix string Text appended to the bubble value (e.g., "%", "°").
data-markers boolean Renders tick marks along the track at each step interval.
data-range-init boolean Set automatically to prevent double-binding. Do not set manually.

Value Bubble

Add data-bubble to display a floating value readout above the thumb. The bubble tracks the thumb position and updates in real time as the user drags.

<label for="brightness">Brightness</label> <input type="range" id="brightness" data-range data-bubble min="0" max="100" value="75">

Prefix and Suffix

Use data-prefix and data-suffix to format the bubble value. The prefix appears before the number and the suffix after it.

<label for="price">Price</label> <input type="range" id="price" data-range data-bubble data-prefix="$" min="0" max="500" value="150"> <label for="opacity">Opacity</label> <input type="range" id="opacity" data-range data-bubble data-suffix="%" min="0" max="100" value="80">

Tick Markers

Add data-markers to render tick marks along the track. Ticks are generated at each step interval between min and max.

<label for="temp">Temperature</label> <input type="range" id="temp" data-range data-bubble data-markers data-suffix="°" min="60" max="90" step="5" value="72">

Datalist Labels

Link a <datalist> via the native list attribute to render labeled tick marks. Each <option> in the datalist becomes a labeled marker on the track.

<label for="rating">Rating</label> <input type="range" id="rating" data-range data-bubble min="1" max="5" step="1" value="3" list="rating-labels"> <datalist id="rating-labels"> <option value="1" label="Poor"></option> <option value="2" label="Fair"></option> <option value="3" label="Good"></option> <option value="4" label="Great"></option> <option value="5" label="Excellent"></option> </datalist>

With Form Field

Wrap in <form-field> for helper text and consistent spacing with other form controls.

<form-field> <label for="quality">Quality</label> <input type="range" id="quality" data-range data-bubble data-suffix="%" min="0" max="100" value="60"> <small slot="help">Adjust the encoding quality.</small> </form-field>

CSS Custom Property

The --range-pct custom property is set on the input element and updated on every input event. Its value ranges from 0% to 100%, representing the thumb position relative to the track. Use it for filled-track effects or other dynamic styling.

/* The --range-pct custom property is updated on every input event */ input[data-range] { --range-pct: 50%; /* default, updated dynamically */ } /* Use it for a filled-track effect */ input[data-range][data-range-init] { background: linear-gradient( to right, var(--color-primary) var(--range-pct), var(--color-border) var(--range-pct) ); }

DOM Structure

After initialization, the following DOM structure is created:

  • .range-wrapper — layout container wrapping the input
  • <output for="inputId"> — the value bubble (only with data-bubble)
  • .range-markers — tick mark container (only with data-markers)
  • .range-labels — label container (only with a linked <datalist>)

Styling

The track and thumb are fully customizable via CSS custom properties. All styles are gated on [data-range-init] so the input renders normally without JavaScript.

/* Track styling */ input[data-range][data-range-init] { --range-track-height: 0.375rem; --range-track-bg: var(--color-border); --range-track-radius: var(--radius-pill); } /* Thumb styling */ input[data-range][data-range-init] { --range-thumb-size: 1.25rem; --range-thumb-bg: var(--color-primary); --range-thumb-border: 2px solid white; --range-thumb-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); } /* Bubble styling */ .range-bubble { --range-bubble-bg: var(--color-surface-raised); --range-bubble-color: var(--color-text); --range-bubble-radius: var(--radius-s); --range-bubble-padding: var(--size-3xs) var(--size-xs); }

Dynamic Elements

Range inputs added to the DOM after page load are automatically enhanced via a MutationObserver. No manual initialization is needed.

// Dynamically added range inputs are auto-enhanced via MutationObserver const input = document.createElement('input'); input.type = 'range'; input.dataset.range = ''; input.dataset.bubble = ''; input.min = '0'; input.max = '100'; input.value = '50'; document.body.appendChild(input); // input is ready to use — no manual init needed

Accessibility

  • The <output for="inputId"> element semantically links the bubble to the input for screen readers
  • Native keyboard support is preserved — arrow keys adjust the value, Home/End jump to min/max
  • A visible <label> is required for the input
  • Tick labels from <datalist> provide additional context for sighted users
  • prefers-reduced-motion: bubble transitions are disabled when reduced motion is preferred
  • Without JavaScript, the range input renders as a standard browser slider — progressive enhancement