Add Range plugin for track fill, value bubble, and tick marks#42525
Merged
Conversation
This was referenced Jun 19, 2026
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.
ce5ced2 to
88b7243
Compare
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. Also wondering if tick mark positioning could be improved a bit - screenshot with element outline on: |
Member
Author
|
Yeah some improvements to be made for sure. Agreed on height and alignment. |
Member
Author
|
Should all be addressed! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


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-valuecustom property that the track gradient consumes.Opt in per input with
data-bs-range; plain.form-rangeinputs are completely unaffected.Features
--range-fill-bg.data-bs-bubble="true") — a floating value that tracks the thumb.data-bs-ticks="true") — generated from a linked<datalist>, with labels from each<option>.Options:
bubble,ticks,formatter. Emitschanged.bs.range.Notes
--range-fill-bgtoken. 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.)inputisn't inEventHandler's native-event list, so it can't be namespaced — it's bound raw and removed explicitly indispose()..form-range ~ .invalid-feedback); instead the parent gets a.range-anchoredpositioning class and decorations position from the input's offset box.Test plan
js/tests/unit/range.spec.js; full Karma suite passes (1113/1113).dist/is intentionally not committed here; CI rebuilds it.