Skip to content

Range Slider

The RangeSlider component creates a numeric range input with optional dual-handle support and value display.

Quick Start

RangeSlider("volume", label="Volume", value=50)

Usage Scenarios

Custom Range

RangeSlider("price", label="Price", min_value=10, max_value=500, step=10, value=100)

Dual Range

RangeSlider(
    "budget",
    label="Budget Range",
    dual=True,
    min_value=0,
    max_value=1000,
    min_selected=100,
    max_selected=500,
    step=50,
)

With Suffix

RangeSlider("temperature", label="Temperature", min_value=-20, max_value=50, value=22, value_suffix="°C")

Parameter Reference

Parameter Type Default Description
name str Required Input name attribute
label str \| None None Label text for the range
help_text str \| None None Help text below the range
min_value int \| float 0 Minimum value
max_value int \| float 100 Maximum value
step int \| float 1 Step increment
value int \| float \| None None Initial value (single mode)
dual bool False Enable dual-handle range
min_name str \| None None Name for min input in dual mode
max_name str \| None None Name for max input in dual mode
min_selected int \| float \| None None Initial min value (dual mode)
max_selected int \| float \| None None Initial max value (dual mode)
show_value bool True Show current value display
value_suffix str "" Suffix appended to displayed value
**kwargs Any - Additional HTML attributes

Accessibility

  • Labels are associated with inputs via for and id attributes.
  • Help text is linked via aria-describedby.
  • Inputs use type="range" with proper min, max, and step attributes.

API Reference

faststrap.components.forms.range_slider.RangeSlider(name, *, label=None, help_text=None, min_value=0, max_value=100, step=1, value=None, dual=False, min_name=None, max_name=None, min_selected=None, max_selected=None, show_value=True, value_suffix='', **kwargs)

Bootstrap range slider.

Source code in src/faststrap/components/forms/range_slider.py
@register(category="forms")
def RangeSlider(
    name: str,
    *,
    label: str | None = None,
    help_text: str | None = None,
    min_value: int | float = 0,
    max_value: int | float = 100,
    step: int | float = 1,
    value: int | float | None = None,
    dual: bool = False,
    min_name: str | None = None,
    max_name: str | None = None,
    min_selected: int | float | None = None,
    max_selected: int | float | None = None,
    show_value: bool = True,
    value_suffix: str = "",
    **kwargs: Any,
) -> Div:
    """Bootstrap range slider."""
    cfg = resolve_defaults(
        "RangeSlider",
        min_value=min_value,
        max_value=max_value,
        step=step,
        dual=dual,
        show_value=show_value,
        value_suffix=value_suffix,
    )
    c_min_value = cfg.get("min_value", min_value)
    c_max_value = cfg.get("max_value", max_value)
    c_step = cfg.get("step", step)
    c_dual = cfg.get("dual", dual)
    c_show_value = cfg.get("show_value", show_value)
    c_value_suffix = cfg.get("value_suffix", value_suffix)

    slider_id = kwargs.pop("id", name)

    def _build_input(input_name: str, input_value: int | float | None, extra_id: str) -> FTInput:
        attrs: dict[str, Any] = {
            "type": "range",
            "name": input_name,
            "id": extra_id,
            "min": str(c_min_value),
            "max": str(c_max_value),
            "step": str(c_step),
            "cls": "form-range",
        }
        if input_value is not None:
            attrs["value"] = str(input_value)
        attrs.update(convert_attrs(kwargs))
        return FTInput(**attrs)

    inputs: list[Any] = []
    value_display = None

    if c_dual:
        min_field = min_name or f"{name}_min"
        max_field = max_name or f"{name}_max"
        inputs.append(_build_input(min_field, min_selected, f"{slider_id}-min"))
        inputs.append(_build_input(max_field, max_selected, f"{slider_id}-max"))
        if c_show_value:
            display = (
                f"{min_selected if min_selected is not None else c_min_value}"
                f"{c_value_suffix} — "
                f"{max_selected if max_selected is not None else c_max_value}{c_value_suffix}"
            )
            value_display = Span(display, cls="small text-muted")
    else:
        inputs.append(_build_input(name, value, slider_id))
        if c_show_value:
            display_value = value if value is not None else c_min_value
            value_display = Span(f"{display_value}{c_value_suffix}", cls="small text-muted")

    nodes: list[Any] = []
    if label:
        nodes.append(Label(label, **{"for": slider_id}, cls="form-label"))

    nodes.extend(inputs)

    if value_display:
        nodes.append(value_display)

    if help_text:
        help_id = f"{slider_id}-help"
        nodes.append(Small(help_text, cls="form-text text-muted", id=help_id))

    return Div(*nodes, cls="mb-3 faststrap-range-slider")