jb-range-input
v0.5.0
Published
Range input web component
Downloads
622
Maintainers
Readme
jb-range-input
jb-range-input is a form-associated, discrete range input web component. It can select one numeric value or a start/end pair; the interactive overview shows the default behavior.
- Supports single-value and two-handle range modes.
- Supports integer and decimal steps.
- Configures selectable steps independently from visible tick marks.
- Supports pointer and keyboard interaction.
- Snaps values to the configured step and constrains them to
minandmax. - Supports native HTML form submission and reset through
ElementInternals. - Supports custom validation through
jb-validation. - Supports TypeScript, ESM, and a React wrapper.
- Supports custom styling with CSS variables, CSS parts, and custom states.
When to use
Use jb-range-input when users should choose a value or interval from a known numeric scale, such as volume, price, score, duration, or filter boundaries; the range example shows interval selection.
Use a number input when users need to enter an exact value directly or the available range is too large to navigate comfortably with a slider.
Demo
Using with React
See the React documentation and its interactive story.
Installation
npm i jb-range-inputimport "jb-range-input";<jb-range-input label="Range value" min="0" max="10" value="4"></jb-range-input>The normal example uses the same basic setup.
CDN
<script src="https://unpkg.com/jb-range-input/web-component/dist/jb-range-input.umd.js"></script>API reference
The API overview demonstrates the main attributes and properties together.
Attributes
The attribute controls show these options in Storybook.
| name | type | default | description |
| --- | --- | --- | --- |
| label | string | "" | Visible label text and accessible aria label. |
| value | number \| "start,end" | single/range mode default | Selected value. In range mode, use a comma-separated pair such as "2,8". |
| mode | "single" \| "range" | "single" | Selects one value or a start/end pair. |
| start-point | number | single-mode default | Start of the active line in single mode. Defaults to 0 when zero is within the range, otherwise min. Ignored in range mode. |
| min | number | 0 | Minimum selectable value. |
| max | number | 10 | Maximum selectable value. |
| step | number | 1 | Increment used to snap selected values and handle keyboard navigation. |
| tick-step | number | 1 | Interval between visible tick marks. It does not constrain selection. |
| minor-tick-step | number | none | Interval between optional minor ticks. Minor ticks never receive labels. |
| show-tick-labels | boolean | false | Displays labels below major ticks. |
| show-persian-number | boolean | locale based | Displays Persian digits in tick labels, slider accessibility text, and the value balloon while keeping .value numeric. |
| disable-balloon-rotation | boolean | false | Disables velocity-based balloon rotation while dragging. |
| size | "xs" \| "sm" \| "md" \| "lg" \| "xl" | "md" | Visual size variant. |
| name | string | "" | Field name used during form submission. |
| disabled | boolean | false | Disables pointer and keyboard interaction. |
| required | boolean | false | Requires a value to be provided initially or selected by the user. |
| message | string | "" | Helper message displayed below the range. |
| error | string | "" | External validation error message. |
Properties
The controlled range example demonstrates property updates.
| name | type | readonly | description |
| --- | --- | --- | --- |
| label | string | no | Visible label text and accessible aria label. |
| value | number \| [number, number] | no | Current normalized value. Returns a tuple in range mode. |
| initialValue | number \| [number, number] | no | Initial and form-reset value. It initializes value until the live value becomes dirty. |
| mode | "single" \| "range" | no | Current selection mode. |
| startPoint | number | no | Start of the active line in single mode. Defaults like the single-mode value and is ignored in range mode. |
| min | number | no | Minimum selectable value. |
| max | number | no | Maximum selectable value. |
| step | number | no | Selectable increment. Non-positive or invalid values normalize to 1. |
| tickStep | number | no | Visible tick interval. Non-positive or invalid values normalize to 1. |
| minorTickStep | number \| null | no | Minor-tick interval, or null to hide minor ticks. |
| showTickLabels | boolean | no | Displays labels below major ticks. |
| showPersianNumber | boolean | no | Overrides locale-based Persian digit display without changing numeric values. |
| disableBalloonRotation | boolean | no | Disables velocity-based balloon rotation while dragging. |
| tickLabelFormatter | (value: number) => string | no | Formats major-tick labels. Functions are configured through JavaScript, not attributes. |
| name | string | no | Associated form field name. |
| disabled | boolean | no | Enables or disables interaction. |
| required | boolean | no | Requires a provided or user-selected value. |
| form | HTMLFormElement \| null | yes | Associated native form. |
| isDirty | boolean | yes | Whether the current value differs from initialValue. |
| validation | ValidationHelper<RangeInputValue> | yes | Shared helper used to configure and run custom validations. |
| isAutoValidationDisabled | boolean | no | Disables automatic validation during user interaction. |
| validationMessage | string | yes | Current message from ElementInternals. |
Methods
The validation example exercises the imperative validity methods.
| name | returns | description |
| --- | --- | --- |
| checkValidity() | boolean | Runs validation without showing the error and dispatches invalid when invalid. |
| reportValidity() | boolean | Runs validation, shows the invalid state, and dispatches invalid when invalid. |
| clearValidationError() | void | Clears the visible invalid state. |
Events
The form example shows the component participating in browser events and submission.
| event | description |
| --- | --- |
| input | Dispatched after a user-selected value is applied. The current value is available on event.target.value. |
| change | Dispatched after a completed pointer or keyboard interaction. |
| invalid | Dispatched by checkValidity() or reportValidity() when validation fails. |
Single-value mode
Single mode renders one handle and returns a number; see the single-value example and the start-point example:
<jb-range-input min="0" max="100" step="5" value="25"></jb-range-input>const rangeInput = document.querySelector("jb-range-input");
rangeInput.value = 40;
console.log(rangeInput.value); // 40Range mode
Range mode renders two handles. The first value cannot move above the second, and the second cannot move below the first; the range story shows the interaction.
When range mode receives one number, that number becomes the upper value and min becomes the lower value. When changing from range mode to single mode, the range's upper value is preserved.
<jb-range-input mode="range" min="0" max="100" value="20,80"></jb-range-input>Use a tuple when assigning the JavaScript property:
const rangeInput = document.querySelector("jb-range-input");
rangeInput.mode = "range";
rangeInput.value = [20, 80];
console.log(rangeInput.value); // [20, 80]Step and tick marks
step controls the values a user can select. tick-step controls the visible tick interval and does not affect selection; compare the decimal-step example.
<jb-range-input
min="0"
max="10"
step="0.1"
tick-step="1"
value="1.2"
></jb-range-input>This configuration allows 0.1, 0.2, 0.3, and so on, while drawing ticks at 0, 1, 2, and so on.
Major ticks can display labels, and optional minor ticks can add visual subdivisions without labels:
<jb-range-input
min="0"
max="100"
step="5"
tick-step="25"
minor-tick-step="5"
show-tick-labels
></jb-range-input>Customize label text with a JavaScript formatter:
const rangeInput = document.querySelector("jb-range-input");
rangeInput.tickLabelFormatter = value => `${value}%`;Values assigned between steps are snapped to the nearest valid step and clamped to the configured bounds.
Size variants
Use xs, sm, md, lg, or xl. Omitting size uses the md styles; the size variants story compares them.
The balloon scales by 15 percentage points between adjacent sizes: 70%, 85%, 100%, 115%, and 130% respectively.
<jb-range-input size="sm" value="4"></jb-range-input>The balloon tilts subtly based on horizontal drag speed and returns to center when movement stops. Disable this motion when a quieter or less resource-intensive interaction is preferred:
<jb-range-input disable-balloon-rotation></jb-range-input>Forms
jb-range-input participates in native forms. Single values are submitted as numeric strings. Range values are submitted as comma-separated strings such as "20,80"; the form example shows submission and reset.
<form id="filters">
<jb-range-input
name="price"
mode="range"
min="0"
max="100"
value="20,80"
></jb-range-input>
<button type="reset">Reset</button>
<button type="submit">Apply</button>
</form>Set initialValue to control the value restored by form reset:
const rangeInput = document.querySelector("jb-range-input");
rangeInput.initialValue = [20, 80];Validation
The component uses jb-validation. Set the error attribute for an external error or configure validation.list for custom rules; see the validation example.
const rangeInput = document.querySelector("jb-range-input");
rangeInput.validation.list = [
{
validator: value => !Array.isArray(value) || value[1] - value[0] >= 10,
message: "The selected range must span at least 10 units",
},
];
rangeInput.reportValidity();Custom validators receive a number in single mode or [number, number] in range mode.
Keyboard interaction
Focus a handle and use the keyboard as shown in the disabled and interaction stories:
ArrowLeftorArrowDownto subtract onestep.ArrowRightorArrowUpto add onestep.
Keyboard changes remain constrained to min, max, and the other handle in range mode.
CSS parts and variables
The styling gallery demonstrates the available theme recipes and customization points.
Parts
The styling gallery shows the exposed parts in context.
| part | description |
| --- | --- |
| root | Root component wrapper. |
| label | Visible label element. |
| range | Main SVG range surface. |
| range-line | Inactive track line. |
| range-active-line | Active track from the minimum or between range handles. |
| range-ticks | Group containing all tick marks. |
| range-tick | Each generated tick mark. |
| range-major-tick | Each generated major tick. |
| range-minor-tick | Each generated minor tick. |
| tick-labels | Container for major-tick labels. |
| tick-label | Each generated major-tick label. |
| range-handles | Group containing the slider handles. |
| range-handle | Each generated slider handle. |
| range-joined-shapes | Filtered group containing the handles and balloon. |
| range-balloon | Balloon displayed while dragging. |
| range-balloon-content | Animated content group inside the balloon. |
| range-balloon-shape | Balloon background path. |
| range-balloon-label | Group containing the balloon value label. |
| range-balloon-value | Text showing the current drag value. |
| message | Helper or validation message below the range. |
Custom states
The disabled and validation stories show the component states.
| state | description |
| --- | --- |
| disabled | Applied when interaction is disabled. |
| required | Applied when required is true. |
| invalid | Applied while a validation error is visible. |
CSS variables
The theme gallery demonstrates these variables across several visual styles.
| variable | default | description |
| --- | --- | --- |
| --jb-range-input-width | 100% | Component width. |
| --jb-range-input-height | 4rem | SVG height. |
| --jb-range-input-label-margin | 0.125rem 0 | Label margin. The component applies range-edge padding separately to align the label with the track. |
| --jb-range-input-label-font-size | 0.8rem | Label font size. |
| --jb-range-input-label-color | --jb-content-primary | Label color. |
| --jb-range-input-label-font-weight | 300 | Label font weight. |
| --jb-range-input-color | --jb-primary | Base color used by active elements. |
| --jb-range-input-line-color | --jb-content-secondary | Inactive line color. |
| --jb-range-input-line-width | 1 | Inactive line stroke width. |
| --jb-range-input-line-dash-array | 2 8 | Inactive line dash pattern. |
| --jb-range-input-active-line-color | base color | Active line color. |
| --jb-range-input-active-line-width | line width + 2 | Active line stroke width. |
| --jb-range-input-active-line-dash-array | 1 0 | Active line dash pattern. |
| --jb-range-input-tick-color | base color | Tick color. |
| --jb-range-input-tick-width | 2px | Tick stroke width. |
| --jb-range-input-tick-height | 0.75rem | Tick height. |
| --jb-range-input-minor-tick-color | major tick color | Minor-tick color. |
| --jb-range-input-minor-tick-width | 1px | Minor-tick stroke width. |
| --jb-range-input-minor-tick-height | half major tick height | Minor-tick height. |
| --jb-range-input-tick-label-color | --jb-content-secondary | Major-tick label color. |
| --jb-range-input-tick-label-font-size | 0.75rem | Major-tick label font size. |
| --jb-range-input-tick-label-line-height | 1.2 | Major-tick label line height. |
| --jb-range-input-tick-label-gap | 0.25rem | Gap between major ticks and their labels. |
| --jb-range-input-handle-color | base color | Handle color. |
| --jb-range-input-handle-size | 0.5rem | Handle radius. |
| --jb-range-input-balloon-color | base color | Drag balloon color. |
| --jb-range-input-balloon-text-color | --jb-content-inverse | Drag balloon text color. |
| --jb-range-input-balloon-font-size | 0.75rem | Drag balloon text size. |
| --jb-range-input-balloon-scale | 1 | Base balloon scale. |
| --jb-range-input-balloon-hover-offset | 0.375rem | Balloon offset above the handle while hovered. |
| --jb-range-input-message-font-size | 0.7rem | Helper/error message font size. |
| --jb-range-input-message-margin | 0 | Message box margin. |
| --jb-range-input-message-box-display | block | Message box display mode. |
| --jb-range-input-message-color | --jb-content-secondary | Helper message color. |
| --jb-range-input-message-color-error | --jb-red | Validation error color. |
| --jb-range-input-color-disabled | --jb-neutral-9 | Base color while disabled. |
| --jb-range-input-line-color-disabled | --jb-neutral-9 | Inactive line color while disabled. |
| --jb-range-input-active-line-color-disabled | disabled base color | Active line color while disabled. |
| --jb-range-input-tick-color-disabled | disabled base color | Tick color while disabled. |
| --jb-range-input-minor-tick-color-disabled | disabled tick color | Minor-tick color while disabled. |
| --jb-range-input-tick-label-color-disabled | --jb-content-secondary | Tick-label color while disabled. |
| --jb-range-input-handle-color-disabled | disabled base color | Handle color while disabled. |
| --jb-range-input-balloon-color-disabled | disabled base color | Balloon color while disabled. |
| --jb-range-input-balloon-text-color-disabled | --jb-content-secondary | Balloon text color while disabled. |
Each size variant also exposes -xs, -sm, -lg, and -xl overrides for height, label-font-size, tick-height, minor-tick-height, handle-size, tick-label-font-size, message-font-size, balloon-scale, and balloon-hover-offset. For example, use --jb-range-input-label-font-size-sm to customize only the sm label.
jb-range-input {
--jb-range-input-color: #2563eb;
--jb-range-input-line-color: #cbd5e1;
--jb-range-input-handle-size: 0.625rem;
}
jb-range-input:state(invalid)::part(range-handle) {
fill: #dc2626;
}Accessibility notes
- Each handle has
role="slider", keyboard focus, andaria-valuemin,aria-valuemax,aria-valuenow, andaria-valuetext, as shown in the normal accessibility example. - The
labelattribute renders a visible label, provides the component's accessible label, and focuses the first handle when clicked. - Disabled handles are removed from the tab order and pointer/keyboard interaction is blocked.
- Required, disabled, and invalid states are exposed through ARIA and custom states.
Related docs
- See
jb-range-input/reactfor React usage and the React story. - See
jb-validationfor custom validation rules. - See All JB Design System components for more components.
- Use the Contribution Guide when contributing.
AI agent notes
- Import
jb-range-inputonce before rendering<jb-range-input>; the overview story is a compact reference. - Use a number in single mode and a
[number, number]tuple in range mode. - The HTML
valueattribute uses a comma-separated string in range mode. stepcontrols selectable values;tick-stepcontrols tick rendering only.- Read the current typed value from
event.target.value. - Form submission serializes a range tuple as a comma-separated string.
- Use
validation.listfor custom validation rules.
