Skip to content

Add Range plugin for track fill, value bubble, and tick marks#42525

Open
mdo wants to merge 8 commits into
v6-devfrom
mdo/customize-range-input
Open

Add Range plugin for track fill, value bubble, and tick marks#42525
mdo wants to merge 8 commits into
v6-devfrom
mdo/customize-range-input

Conversation

@mdo

@mdo mdo commented Jun 18, 2026

Copy link
Copy Markdown
Member

Summary

Adds an opt-in JavaScript plugin that enhances <input type="range">, building on the idea from #37499 and taking it further into a proper plugin.

A consistent cross-browser fill cannot be done with pseudo-elements alone — only Firefox has ::-moz-range-progress; WebKit/Blink have no equivalent and CSS can't read an input's value. So the plugin publishes the current value as a --bs-range-value custom property that the track gradient consumes.

Opt in per input with data-bs-range; plain .form-range inputs are completely unaffected.

Features

  • Fill — colored track up to the thumb, themeable via --range-fill-bg.
  • Value bubble (data-bs-bubble="true") — a floating value that tracks the thumb.
  • Tick marks (data-bs-ticks="true") — generated from a linked <datalist>, with labels from each <option>.

Options: bubble, ticks, formatter. Emits changed.bs.range.

Notes

  • The bubble and tick marks are siblings of the input, so they don't inherit the input's --range-fill-bg token. The plugin copies the input's resolved fill color onto them, and the CSS falls back to --primary-base, so they're never rendered blank. (This was the cause of an invisible bubble in early testing.)
  • input isn't in EventHandler's native-event list, so it can't be namespaced — it's bound raw and removed explicitly in dispose().
  • The input is intentionally not wrapped (wrapping would break validation's .form-range ~ .invalid-feedback); instead the parent gets a .range-anchored positioning class and decorations position from the input's offset box.

Test plan

  • New js/tests/unit/range.spec.js; full Karma suite passes (1113/1113).
  • Verified rendering in WebKit (Playwright) — fill, bubble, and ticks all render correctly.
  • ESLint, Stylelint, markdownlint, and Prettier all clean.

dist/ is intentionally not committed here; CI rebuilds it.

mdo added 6 commits June 20, 2026 22:02
Adds an opt-in JavaScript plugin (`data-bs-range`) that enhances
`<input type="range">`. A consistent cross-browser fill can't be done
with pseudo-elements alone (only Firefox has `::-moz-range-progress`),
so the plugin publishes the current value as a `--bs-range-value`
custom property that the track gradient consumes.

- Fill: colored track up to the thumb, themeable via `--range-fill-bg`
- Value bubble (`data-bs-bubble`): floating value that tracks the thumb
- Tick marks (`data-bs-ticks`): generated from a linked `<datalist>`

The bubble and ticks are siblings of the input, so they don't inherit
the input's `--range-fill-bg`; the plugin copies the resolved value onto
them and the CSS falls back to `--primary-base` so they're never blank.

Plain `.form-range` inputs are untouched. Includes unit tests and docs.
- Make `.form-range` the positioning context (`position: relative`) and
  drop the JS-added `.range-anchored` class; the bubble and ticks are
  siblings of the input, so they already share its offset parent.
- Rename `--range-fill-bg` to `--range-track-fill-bg` for accuracy.
- Keep SCSS custom properties unprefixed (the build adds `--bs-`) and
  have the plugin read/write the prefixed names, matching the codebase.
- Trim obvious comments.
Restructure range as an always-JS component so the fill, value bubble,
and tick marks are driven by a single `--bs-range-fill` ratio in CSS.

- `.form-range` is now a wrapper that owns the tokens; the input takes
  `.form-range-input`. Children inherit the tokens, so the old JS color
  copying and px positioning are gone.
- The plugin only sets `--bs-range-fill` (0–1) and the bubble text; the
  track gradient, bubble position, and tick positions are pure CSS calc.
  Drops `_thumbWidth`, `_inheritFillColor`, the resize listener, and the
  `.range-anchored` class.
- Value bubble reuses the tooltip markup/styles instead of duplicating a
  pill and arrow. Tick marks are generated from the linked `<datalist>`
  and positioned per-value (handles uneven values); tick coloring dropped.
- Auto-inits every `.form-range`; rename fill token to
  `--range-track-fill-bg`.
- Validation moves to `.form-range-input` with a `:has()` feedback toggle.
- Add the "New" badge to the Range sidebar item and document the breaking
  changes in the migration guide.
Build `grid-template-columns` from the gaps between the datalist values
so each tick lands on a grid line — this handles unevenly-spaced values
just like the old per-tick calc did, but keeps the ticks and their labels
in normal flow (the container sizes to fit the labels instead of them
overflowing an absolutely-positioned box). Inset by half the thumb so the
end ticks align with the thumb travel.

Also wraps the token map in the `custom-property-no-missing-var-function`
stylelint disable (matching _strength.scss). Includes the disabled-track
fill styling.
@mdo mdo force-pushed the mdo/customize-range-input branch from ce5ced2 to 88b7243 Compare June 21, 2026 05:05
@coliff

coliff commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

PREVIEW: https://deploy-preview-42525--twbs-bootstrap.netlify.app/docs/6.0/forms/range/

love it! Tested on Firefox (Windows), Edge (Windows), Chrome (Windows) and iPadOS 27 Beta.

The tick marks are very subtle though. I think they could do with being a bit taller and having more contrast.
tick mark contrast

Also wondering if tick mark positioning could be improved a bit - screenshot with element outline on:
tick mark positioning

@mdo

mdo commented Jun 21, 2026

Copy link
Copy Markdown
Member Author

Yeah some improvements to be made for sure. Agreed on height and alignment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Inbox

Development

Successfully merging this pull request may close these issues.

2 participants