> Markdown version of [Slider](https://vaadin.com/docs/latest/components/slider). Section index: [llms.txt](https://vaadin.com/docs/latest/components/llms.txt)

# Slider (since V25.1)

Slider is an input field that lets users pick a numeric value within a range by dragging a thumb along a track. Use arrow keys for precise adjustments.

**Lit** — `slider-basic.ts`

```typescript
<vaadin-slider label="Volume" value="50"></vaadin-slider>
```

**Flow** — `SliderBasic.java`

```java
IntegerSlider slider = new IntegerSlider("Volume");
slider.setValue(50);
add(slider);
```

**React** — `slider-basic.tsx`

```tsx
<Slider label="Volume" value={50} />
```

## <a id="range-slider"></a>Range Slider

Range Slider is a two-thumb variant of Slider for selecting a numeric range. It supports the same features as Slider, but its value is a pair of numbers representing the start and end of the selected range.

**Lit** — `range-slider-basic.ts`

```typescript
<vaadin-range-slider
  label="Price range"
  min="0"
  max="1000"
  .value="${[200, 800]}"
></vaadin-range-slider>
```

**Flow** — `RangeSliderBasic.java`

```java
IntegerRangeSlider rangeSlider = new IntegerRangeSlider("Price range",
        0, 1000);
rangeSlider.setValue(new IntegerRangeSliderValue(200, 800));
add(rangeSlider);
```

**React** — `range-slider-basic.tsx`

```tsx
<RangeSlider label="Price range" min={0} max={1000} value={[200, 800]} />
```

## <a id="value-types"></a>Value Types

In Flow, separate classes are provided for integer and decimal values. For integer values, use `IntegerSlider` or `IntegerRangeSlider`, which have `Integer` as their value type. For decimal values, use `DecimalSlider` or `DecimalRangeSlider`, which have `Double` as their value type. The value type determines the type used to configure the slider’s value and constraints (minimum, maximum, step).

In React and Lit, there are no separate components for integer and decimal values. A single `Slider` and `RangeSlider` component handles both, using the JavaScript `number` type.

## <a id="min-max-labels"></a>Min & Max Labels

The minimum and maximum values can be displayed below the slider track to give users a sense of the available range.

**Lit** — `slider-min-max-visible.ts`

```typescript
<vaadin-slider
  label="Temperature"
  min="0"
  max="100"
  value="50"
  min-max-visible
></vaadin-slider>
```

**Flow** — `SliderMinMaxVisible.java`

```java
IntegerSlider slider = new IntegerSlider("Temperature", 0, 100);
slider.setValue(50);
slider.setMinMaxVisible(true);
add(slider);
```

**React** — `slider-min-max-visible.tsx`

```tsx
<Slider label="Temperature" min={0} max={100} value={50} minMaxVisible />
```

## <a id="persistent-value-display"></a>Persistent Value Display

By default, the value bubble appears only when the user interacts with the slider. It’s possible to configure the slider to keep the value bubble visible at all times.

**Lit** — `slider-value-always-visible.ts`

```typescript
<vaadin-slider
  label="Brightness"
  min="0"
  max="100"
  value="75"
  value-always-visible
></vaadin-slider>
```

**Flow** — `SliderValueAlwaysVisible.java`

```java
IntegerSlider slider = new IntegerSlider("Brightness", 0, 100);
slider.setValue(75);
slider.setValueAlwaysVisible(true);
add(slider);
```

**React** — `slider-value-always-visible.tsx`

```tsx
<Slider label="Brightness" min={0} max={100} value={75} valueAlwaysVisible />
```

## <a id="step"></a>Step

The `step` property controls the increment interval between selectable values. The default step is `1`. Fractional values like `0.5` are supported for finer control. Steps are calculated relative to the min value.

**Lit** — `slider-step.ts`

```typescript
<vaadin-slider label="Volume" min="0" max="10" value="5" step="0.5"></vaadin-slider>
```

**Flow** — `SliderStep.java`

```java
DecimalSlider slider = new DecimalSlider("Volume", 0, 10);
slider.setValue(5.0);
slider.setStep(0.5);
add(slider);
```

**React** — `slider-step.tsx`

```tsx
<Slider label="Volume" min={0} max={10} value={5} step={0.5} />
```

## <a id="basic-features"></a>Basic Features

The following features, common to most input field components, are supported:

Label

The label is used to identify the input field. It supports plain-text content. In the Lumo theme its length is limited to the width of the field (and truncated with ellipsis), while in the Aura theme labels wrap to multiple lines. [Helpers](#helper) and [Tooltips](#tooltip) can be used to provide additional information that doesn’t fit into the label.

Visible labels are strongly recommended for all input fields. In cases where the built-in label cannot be used, an external element can be associated as the field’s label through the `aria-labelledby` attribute (`setAriaLabelledBy` in Flow). Fields without any visible label should include an invisible label for assistive technologies with the `aria-label` attribute (`setAriaLabel` in Flow).

Helper

Helpers are used to provide additional information that the user may need to enter in the field, such as format requirements or explanations of the field’s purpose below the field.

A [style variant](https://vaadin.com/docs/latest/components/slider/styling.md#style-variants) is available for rendering the helper above the field.

In addition to plain text, helpers can contain components and HTML elements. However, complex and interactive content is likely to have accessibility issues.

**Lit** — `slider-basic-features.ts`

```typescript
<vaadin-slider label="Label" helper-text="Helper text"></vaadin-slider>
```

**Flow** — `SliderBasicFeatures.java`

```java
IntegerSlider slider = new IntegerSlider("Label");
slider.setHelperText("Helper text");
add(slider);
```

**React** — `slider-basic-features.tsx`

```tsx
<Slider label="Label" helperText="Helper text" />
```

## <a id="read-only-disabled"></a>Read-Only & Disabled

Fields used to display values should be set to `read-only` mode to prevent editing. Read-only fields are focusable and visible to screen readers. They can display tooltips. Their values can be selected and copied.

Fields that are currently unavailable should be `disabled`. The reduced contrast of disabled fields makes them inappropriate for displaying information. They can’t be focused or display tooltips. They’re invisible to screen readers, and their values cannot be selected and copied.

Disabled fields can be useful in situations where they can become enabled based on some user action. Consider hiding fields entirely if there’s nothing the user can do to make them editable.

**Lit** — `slider-readonly-and-disabled.ts`

```typescript
<vaadin-slider readonly label="Read-only" value="50"></vaadin-slider>

<vaadin-slider disabled label="Disabled"></vaadin-slider>
```

**Flow** — `SliderReadonlyAndDisabled.java`

```java
IntegerSlider readonlySlider = new IntegerSlider("Read-only");
readonlySlider.setValue(50);
readonlySlider.setReadOnly(true);

IntegerSlider disabledSlider = new IntegerSlider("Disabled");
disabledSlider.setEnabled(false);
```

**React** — `slider-readonly-and-disabled.tsx`

```tsx
<Slider readonly label="Read-only" value={50} />

<Slider disabled label="Disabled" />
```

## <a id="accessible-thumb-names"></a>Accessible Thumb Names

Range Slider has two thumbs, each with a default accessible name derived from the label (e.g., "Price range min" and "Price range max"). It’s possible to provide custom accessible names for each thumb to improve the experience for screen reader users.

**Lit** — `range-slider-accessible-name.ts`

```typescript
<vaadin-range-slider
  label="Price range"
  min="0"
  max="1000"
  .value="${[200, 800]}"
  accessible-name-start="Minimum price"
  accessible-name-end="Maximum price"
></vaadin-range-slider>
```

**Flow** — `RangeSliderAccessibleName.java`

```java
IntegerRangeSlider rangeSlider = new IntegerRangeSlider("Price range",
        0, 1000);
rangeSlider.setValue(new IntegerRangeSliderValue(200, 800));
rangeSlider.setAccessibleNameStart("Minimum price");
rangeSlider.setAccessibleNameEnd("Maximum price");
add(rangeSlider);
```

**React** — `range-slider-accessible-name.tsx`

```tsx
<RangeSlider
  label="Price range"
  min={0}
  max={1000}
  value={[200, 800]}
  accessibleNameStart="Minimum price"
  accessibleNameEnd="Maximum price"
/>
```

## <a id="validation"></a>Validation

Unlike other input fields, Slider and Range Slider don’t have built-in constraint validation. However, they do support invalid state and error messages, so you can implement custom validation logic.

The following example validates that the selected price range spans at least $200. Try narrowing the range to less than $200 to see the validation error:

**Lit** — `range-slider-custom-validation.ts`

```typescript
<vaadin-range-slider
  label="Price Range"
  min="0"
  max="1000"
  step="50"
  .value="${this.value}"
  .invalid="${this.invalid}"
  .errorMessage="${this.errorMessage}"
  @change="${(e: RangeSliderChangeEvent) => {
    this.value = e.target.value;
    const [start, end] = e.target.value;
    if (end - start < 200) {
      this.errorMessage = 'Price range must span at least $200';
      this.invalid = true;
    } else {
      this.invalid = false;
    }
  }}"
></vaadin-range-slider>
```

**Flow** — `RangeSliderCustomValidation.java`

```java
IntegerRangeSlider rangeSlider = new IntegerRangeSlider("Price Range",
        0, 1000);
rangeSlider.setStep(50);
rangeSlider.setMinMaxVisible(true);

Binder<PriceFilter> binder = new Binder<>();
binder.forField(rangeSlider)
        .withValidator(value -> value.end() - value.start() >= 200,
                "Price range must span at least $200")
        .bind(product -> {
            return new IntegerRangeSliderValue(product.getMinPrice(),
                    product.getMaxPrice());
        }, (product, value) -> {
            product.setMinPrice(value.start());
            product.setMaxPrice(value.end());
        });

binder.setBean(new PriceFilter());

add(rangeSlider);
```

**React** — `range-slider-custom-validation.tsx`

```tsx
const currentValue = useSignal<number[]>([200, 800]);
const errorMessage = useSignal('');
const invalid = useSignal(false);

return (
  <RangeSlider
    label="Price Range"
    min={0}
    max={1000}
    step={50}
    value={currentValue.value}
    invalid={invalid.value}
    errorMessage={errorMessage.value}
    onChange={(e: RangeSliderChangeEvent) => {
      currentValue.value = e.target.value;
      const [start, end] = e.target.value;
      if (end - start < 200) {
        errorMessage.value = 'Price range must span at least $200';
        invalid.value = true;
      } else {
        errorMessage.value = '';
        invalid.value = false;
      }
    }}
  />
);
```

## <a id="value-change-modes-flow"></a>Value Change Modes Flow

With the Flow Java API, you can define when client-side value changes are synchronized to the server. The `ValueChangeMode` enum provides the following modes:

| Mode                  | Synchronization timing                                                                                                                                           | Custom timeout interval |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
| `EAGER`               | Synchronizes the value whenever it changes on the client side, for example on each keystroke.                                                                    | No                      |
| `LAZY`                | Synchronizes the value after a defined interval has passed without further changes. If another change occurs before the interval ends, the timeout is restarted. | Yes                     |
| `TIMEOUT`             | Synchronizes the value at defined intervals while the value continues to change.                                                                                 | Yes                     |
| `ON_CHANGE` (default) | Synchronizes the value on the `change` event, when the component value is committed.                                                                             | No                      |

For the modes that support a custom timeout interval, you can change the interval with the `setValueChangeTimeout()` method. The default interval is 400 milliseconds.

**Flow** — `SliderValueChangeMode.java`

```java
var slider = new DecimalSlider("Slider");
slider.setValue(50.0);
var modeSelector = new Select<>("Value Change Mode", valueChangeModes);
modeSelector.setValue(slider.getValueChangeMode());
modeSelector.addValueChangeListener(e -> {
    slider.setValue(50.0);
    slider.setValueChangeMode(e.getValue());
});
var serverSideContent = new Span();
slider.addValueChangeListener(e -> serverSideContent
        .setText(e.getValue() == null ? "" : e.getValue().toString()));
```

## <a id="best-practices"></a>Best Practices

Slider is best suited for settings where the user benefits from immediate visual feedback, such as adjusting volume or brightness. Range Slider is best suited for filtering or selecting a subset of a continuous range, such as a price range or date span.

When setting `min`, `max`, and `step`, choose values that result in a reasonable number of selectable steps. Too many steps make precise selection difficult; too few limit the user’s options.

## <a id="related-components"></a>Related Components

| Component                                                                 | Usage Recommendation                                 |
| ------------------------------------------------------------------------- | ---------------------------------------------------- |
| [Number Field](https://vaadin.com/docs/latest/components/number-field.md) | For precise numeric input where exact values matter. |
