FORMATTER = (
+ component, value) -> {
+ component.requireValidValue(value);
+
+ return JacksonUtils
+ .listToJson(Arrays.asList(value.start(), value.end()));
+ };
+
+ /**
+ * Constructs a {@code RangeSlider} with range 0-100 and initial value
+ * 0-100.
+ *
+ * The step defaults to 1.
+ */
+ public RangeSlider() {
+ this(DEFAULT_MIN, DEFAULT_MAX, DEFAULT_STEP,
+ new RangeSliderValue(DEFAULT_MIN, DEFAULT_MAX));
+ }
+
+ /**
+ * Constructs a {@code RangeSlider} with range 0-100, initial value 0-100,
+ * and a value change listener.
+ *
+ * The step defaults to 1.
+ *
+ * @param listener
+ * the value change listener
+ */
+ public RangeSlider(
+ ValueChangeListener super ComponentValueChangeEvent> listener) {
+ this(DEFAULT_MIN, DEFAULT_MAX, DEFAULT_STEP,
+ new RangeSliderValue(DEFAULT_MIN, DEFAULT_MAX), listener);
+ }
+
+ /**
+ * Constructs a {@code RangeSlider} with the given range and initial value.
+ *
+ * The step defaults to 1.
+ *
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param value
+ * the initial value
+ */
+ public RangeSlider(double min, double max, RangeSliderValue value) {
+ this(min, max, DEFAULT_STEP, value);
+ }
+
+ /**
+ * Constructs a {@code RangeSlider} with the given range, initial value, and
+ * a value change listener.
+ *
+ * The step defaults to 1.
+ *
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param value
+ * the initial value
+ * @param listener
+ * the value change listener
+ */
+ public RangeSlider(double min, double max, RangeSliderValue value,
+ ValueChangeListener super ComponentValueChangeEvent> listener) {
+ this(min, max, DEFAULT_STEP, value, listener);
+ }
+
+ /**
+ * Constructs a {@code RangeSlider} with the given range, step, and initial
+ * value.
+ *
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param step
+ * the step value
+ * @param value
+ * the initial value
+ */
+ public RangeSlider(double min, double max, double step,
+ RangeSliderValue value) {
+ super(min, max, step, value, ArrayNode.class, PARSER, FORMATTER);
+ }
+
+ /**
+ * Constructs a {@code RangeSlider} with the given range, step, initial
+ * value, and a value change listener.
+ *
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param step
+ * the step value
+ * @param value
+ * the initial value
+ * @param listener
+ * the value change listener
+ */
+ public RangeSlider(double min, double max, double step,
+ RangeSliderValue value,
+ ValueChangeListener super ComponentValueChangeEvent> listener) {
+ this(min, max, step, value);
+ addValueChangeListener(listener);
+ }
+
+ /**
+ * Constructs a {@code RangeSlider} with the given label, range 0-100, and
+ * initial value 0-100.
+ *
+ * The step defaults to 1.
+ *
+ * @param label
+ * the text to set as the label
+ */
+ public RangeSlider(String label) {
+ this();
+ setLabel(label);
+ }
+
+ /**
+ * Constructs a {@code RangeSlider} with the given label, range 0-100,
+ * initial value 0-100, and a value change listener.
+ *
+ * The step defaults to 1.
+ *
+ * @param label
+ * the text to set as the label
+ * @param listener
+ * the value change listener
+ */
+ public RangeSlider(String label,
+ ValueChangeListener super ComponentValueChangeEvent> listener) {
+ this(listener);
+ setLabel(label);
+ }
+
+ /**
+ * Constructs a {@code RangeSlider} with the given label, range, and initial
+ * value.
+ *
+ * The step defaults to 1.
+ *
+ * @param label
+ * the text to set as the label
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param value
+ * the initial value
+ */
+ public RangeSlider(String label, double min, double max,
+ RangeSliderValue value) {
+ this(min, max, value);
+ setLabel(label);
+ }
+
+ /**
+ * Constructs a {@code RangeSlider} with the given label, range, initial
+ * value, and a value change listener.
+ *
+ * The step defaults to 1.
+ *
+ * @param label
+ * the text to set as the label
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param value
+ * the initial value
+ * @param listener
+ * the value change listener
+ */
+ public RangeSlider(String label, double min, double max,
+ RangeSliderValue value,
+ ValueChangeListener super ComponentValueChangeEvent> listener) {
+ this(min, max, value, listener);
+ setLabel(label);
+ }
+
+ /**
+ * Constructs a {@code RangeSlider} with the given label, range, step, and
+ * initial value.
+ *
+ * @param label
+ * the text to set as the label
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param step
+ * the step value
+ * @param value
+ * the initial value
+ */
+ public RangeSlider(String label, double min, double max, double step,
+ RangeSliderValue value) {
+ this(min, max, step, value);
+ setLabel(label);
+ }
+
+ /**
+ * Constructs a {@code RangeSlider} with the given label, range, step,
+ * initial value, and a value change listener.
+ *
+ * @param label
+ * the text to set as the label
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param step
+ * the step value
+ * @param value
+ * the initial value
+ * @param listener
+ * the value change listener
+ */
+ public RangeSlider(String label, double min, double max, double step,
+ RangeSliderValue value,
+ ValueChangeListener super ComponentValueChangeEvent> listener) {
+ this(min, max, step, value, listener);
+ setLabel(label);
+ }
+
+ /**
+ * Sets the minimum value of the slider.
+ *
+ * @param min
+ * the minimum value
+ * @throws IllegalArgumentException
+ * if the min is greater than the max value
+ * @throws IllegalArgumentException
+ * if the current start value is below the new minimum value
+ */
+ public void setMin(double min) {
+ if (getValue().start() < min) {
+ throw new IllegalArgumentException(
+ "The current start value {} is below the new minimum value {}"
+ .formatted(getValue().start(), min));
+ }
+
+ super.setMinDouble(min);
+ }
+
+ /**
+ * Gets the minimum value of the slider.
+ *
+ * @return the minimum value
+ */
+ public double getMin() {
+ return getMinDouble();
+ }
+
+ /**
+ * Sets the maximum value of the slider.
+ *
+ * @param max
+ * the maximum value
+ * @throws IllegalArgumentException
+ * if the max is less than the min value
+ * @throws IllegalArgumentException
+ * if the current end value exceeds the new maximum value
+ */
+ public void setMax(double max) {
+ if (getValue().end() > max) {
+ throw new IllegalArgumentException(
+ "The current end value {} exceeds the new maximum value {}"
+ .formatted(getValue().end(), max));
+ }
+
+ super.setMaxDouble(max);
+ }
+
+ /**
+ * Gets the maximum value of the slider.
+ *
+ * @return the maximum value
+ */
+ public double getMax() {
+ return getMaxDouble();
+ }
+
+ /**
+ * Sets the step value of the slider. The step is the amount the value
+ * changes when the user moves a handle.
+ *
+ * @param step
+ * the step value
+ * @throws IllegalArgumentException
+ * if the step is less than or equal to zero
+ * @throws IllegalArgumentException
+ * if the current value is not aligned with the new step value
+ */
+ public void setStep(double step) {
+ if (getValue().start() % step != 0 || getValue().end() % step != 0) {
+ throw new IllegalArgumentException(
+ "The current value [{}, {}] is not aligned with the new step value {}"
+ .formatted(getValue().start(), getValue().end(),
+ step));
+ }
+
+ super.setStepDouble(step);
+ }
+
+ /**
+ * Gets the step value of the slider.
+ *
+ * @return the step value
+ */
+ public double getStep() {
+ return getStepDouble();
+ }
+
+ private RangeSliderValue requireValidValue(RangeSliderValue value) {
+ Objects.requireNonNull(value, "Value cannot be null");
+
+ if (value.start() < getMin() || value.end() > getMax()) {
+ throw new IllegalArgumentException(
+ "The value must be between min and max");
+ }
+
+ if (value.start() % getStep() != 0 || value.end() % getStep() != 0) {
+ throw new IllegalArgumentException(
+ "The value is not aligned with the step value");
+ }
+
+ return value;
+ }
+}
diff --git a/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/java/com/vaadin/flow/component/slider/RangeSliderValue.java b/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/java/com/vaadin/flow/component/slider/RangeSliderValue.java
new file mode 100644
index 00000000000..76a9d7e3300
--- /dev/null
+++ b/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/java/com/vaadin/flow/component/slider/RangeSliderValue.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2000-2026 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.flow.component.slider;
+
+import java.io.Serializable;
+
+/**
+ * Represents the value of a {@link RangeSlider}, consisting of a start and end
+ * value.
+ *
+ * @param start
+ * the start value of the range
+ * @param end
+ * the end value of the range
+ *
+ * @author Vaadin Ltd
+ */
+public record RangeSliderValue(double start,
+ double end) implements Serializable {
+
+ /**
+ * Creates a new RangeSliderValue with the given start and end values.
+ *
+ * @param start
+ * the start value of the range
+ * @param end
+ * the end value of the range
+ * @throws IllegalArgumentException
+ * if start is greater than end
+ */
+ public RangeSliderValue {
+ if (start > end) {
+ throw new IllegalArgumentException(
+ "Start value cannot be greater than end value");
+ }
+ }
+}
diff --git a/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/java/com/vaadin/flow/component/slider/Slider.java b/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/java/com/vaadin/flow/component/slider/Slider.java
new file mode 100644
index 00000000000..a7301acb602
--- /dev/null
+++ b/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/java/com/vaadin/flow/component/slider/Slider.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2000-2026 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.flow.component.slider;
+
+import java.util.Objects;
+
+import com.vaadin.flow.component.Tag;
+import com.vaadin.flow.function.SerializableBiFunction;
+
+/**
+ * Slider is an input field that allows the user to select a numeric value
+ * within a range by dragging a handle along a track or using arrow keys for
+ * precise input.
+ *
+ * @author Vaadin Ltd.
+ */
+@Tag("vaadin-slider")
+// @NpmPackage(value = "@vaadin/slider", version = "25.1.0-alpha1")
+// @JsModule("@vaadin/slider/src/vaadin-slider.js")
+public class Slider extends SliderBase {
+ private static final double DEFAULT_MIN = 0;
+ private static final double DEFAULT_MAX = 100;
+ private static final double DEFAULT_STEP = 1;
+
+ private static final SerializableBiFunction PARSER = (component, value) -> {
+ return component.requireValidValue(value);
+ };
+
+ private static final SerializableBiFunction FORMATTER = (component, value) -> {
+ return component.requireValidValue(value);
+ };
+
+ /**
+ * Constructs a {@code Slider} with range 0-100 and initial value 0.
+ *
+ * The step defaults to 1.
+ */
+ public Slider() {
+ this(DEFAULT_MIN, DEFAULT_MAX, DEFAULT_STEP, DEFAULT_MIN);
+ }
+
+ /**
+ * Constructs a {@code Slider} with range 0-100, initial value 0, and a
+ * value change listener.
+ *
+ * The step defaults to 1.
+ *
+ * @param listener
+ * the value change listener
+ */
+ public Slider(
+ ValueChangeListener super ComponentValueChangeEvent> listener) {
+ this(DEFAULT_MIN, DEFAULT_MAX, DEFAULT_STEP, DEFAULT_MIN, listener);
+ }
+
+ /**
+ * Constructs a {@code Slider} with the given range and initial value.
+ *
+ * The step defaults to 1.
+ *
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param value
+ * the initial value
+ */
+ public Slider(double min, double max, double value) {
+ this(min, max, DEFAULT_STEP, value);
+ }
+
+ /**
+ * Constructs a {@code Slider} with the given range, initial value, and a
+ * value change listener.
+ *
+ * The step defaults to 1.
+ *
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param value
+ * the initial value
+ * @param listener
+ * the value change listener
+ */
+ public Slider(double min, double max, double value,
+ ValueChangeListener super ComponentValueChangeEvent> listener) {
+ this(min, max, DEFAULT_STEP, value, listener);
+ }
+
+ /**
+ * Constructs a {@code Slider} with the given range, step, and initial
+ * value.
+ *
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param step
+ * the step value
+ * @param value
+ * the initial value
+ */
+ public Slider(double min, double max, double step, double value) {
+ super(min, max, step, value, Double.class, PARSER, FORMATTER);
+ }
+
+ /**
+ * Constructs a {@code Slider} with the given range, step, initial value,
+ * and a value change listener.
+ *
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param step
+ * the step value
+ * @param value
+ * the initial value
+ * @param listener
+ * the value change listener
+ */
+ public Slider(double min, double max, double step, double value,
+ ValueChangeListener super ComponentValueChangeEvent> listener) {
+ this(min, max, step, value);
+ addValueChangeListener(listener);
+ }
+
+ /**
+ * Constructs a {@code Slider} with the given label, range 0-100, and
+ * initial value 0.
+ *
+ * The step defaults to 1.
+ *
+ * @param label
+ * the text to set as the label
+ */
+ public Slider(String label) {
+ this();
+ setLabel(label);
+ }
+
+ /**
+ * Constructs a {@code Slider} with the given label, range 0-100, initial
+ * value 0, and a value change listener.
+ *
+ * The step defaults to 1.
+ *
+ * @param label
+ * the text to set as the label
+ * @param listener
+ * the value change listener
+ */
+ public Slider(String label,
+ ValueChangeListener super ComponentValueChangeEvent> listener) {
+ this(listener);
+ setLabel(label);
+ }
+
+ /**
+ * Constructs a {@code Slider} with the given label, range, and initial
+ * value.
+ *
+ * The step defaults to 1.
+ *
+ * @param label
+ * the text to set as the label
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param value
+ * the initial value
+ */
+ public Slider(String label, double min, double max, double value) {
+ this(min, max, value);
+ setLabel(label);
+ }
+
+ /**
+ * Constructs a {@code Slider} with the given label, range, initial value,
+ * and a value change listener.
+ *
+ * @param label
+ * the text to set as the label
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param value
+ * the initial value
+ * @param listener
+ * the value change listener
+ */
+ public Slider(String label, double min, double max, double value,
+ ValueChangeListener super ComponentValueChangeEvent> listener) {
+ this(min, max, value, listener);
+ setLabel(label);
+ }
+
+ /**
+ * Constructs a {@code Slider} with the given label, range, step, and
+ * initial value.
+ *
+ * @param label
+ * the text to set as the label
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param step
+ * the step value
+ * @param value
+ * the initial value
+ */
+ public Slider(String label, double min, double max, double step,
+ double value) {
+ this(min, max, step, value);
+ setLabel(label);
+ }
+
+ /**
+ * Constructs a {@code Slider} with the given label, range, step, initial
+ * value, and a value change listener.
+ *
+ * @param label
+ * the text to set as the label
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param step
+ * the step value
+ * @param value
+ * the initial value
+ * @param listener
+ * the value change listener
+ */
+ public Slider(String label, double min, double max, double step,
+ double value,
+ ValueChangeListener super ComponentValueChangeEvent> listener) {
+ this(min, max, step, value, listener);
+ setLabel(label);
+ }
+
+ /**
+ * Sets the minimum value of the slider.
+ *
+ * @param min
+ * the minimum value
+ * @throws IllegalArgumentException
+ * if the min is greater than the max value
+ * @throws IllegalArgumentException
+ * if the current value is less than the new minimum value
+ */
+ public void setMin(double min) {
+ if (getValue() < min) {
+ throw new IllegalArgumentException(
+ "The current value {} is less than the new minimum value {}".formatted(
+ getValue(), min));
+ }
+
+ super.setMinDouble(min);
+ }
+
+ /**
+ * Gets the minimum value of the slider.
+ *
+ * @return the minimum value
+ */
+ public double getMin() {
+ return getMinDouble();
+ }
+
+ /**
+ * Sets the maximum value of the slider.
+ *
+ * @param max
+ * the maximum value
+ * @throws IllegalArgumentException
+ * if the max is less than the min value
+ * @throws IllegalArgumentException
+ * if the current value is greater than the new maximum value
+ */
+ public void setMax(double max) {
+ if (getValue() > max) {
+ throw new IllegalArgumentException(
+ "The current value {} is greater than the new maximum value {}".formatted(
+ getValue(), max));
+ }
+
+ super.setMaxDouble(max);
+ }
+
+ /**
+ * Gets the maximum value of the slider.
+ *
+ * @return the maximum value
+ */
+ public double getMax() {
+ return getMaxDouble();
+ }
+
+ /**
+ * Sets the step value of the slider. The step is the amount the value
+ * changes when the user moves the handle.
+ *
+ * @param step
+ * the step value
+ * @throws IllegalArgumentExceptionm
+ * if the step is less than or equal to zero
+ * @throws IllegalArgumentException
+ * if the current value is not aligned with the new step value
+ */
+ public void setStep(double step) {
+ if (getValue() % step != 0) {
+ throw new IllegalArgumentException(
+ "The current value {} is not aligned with the new step value {}".formatted(
+ getValue(), step));
+ }
+
+ super.setStepDouble(step);
+ }
+
+ /**
+ * Gets the step value of the slider.
+ *
+ * @return the step value
+ */
+ public double getStep() {
+ return getStepDouble();
+ }
+
+ private double requireValidValue(Double value) {
+ Objects.requireNonNull(value, "Value cannot be null");
+
+ if (value < getMin() || value > getMax()) {
+ throw new IllegalArgumentException(
+ "The value must be between min and max");
+ }
+
+ if (value % getStep() != 0) {
+ throw new IllegalArgumentException(
+ "The value is not aligned with the step value");
+ }
+
+ return value;
+ }
+}
diff --git a/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/java/com/vaadin/flow/component/slider/SliderBase.java b/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/java/com/vaadin/flow/component/slider/SliderBase.java
new file mode 100644
index 00000000000..c1f6892875e
--- /dev/null
+++ b/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/java/com/vaadin/flow/component/slider/SliderBase.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2000-2026 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.flow.component.slider;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.vaadin.experimental.FeatureFlags;
+import com.vaadin.flow.component.AbstractSinglePropertyField;
+import com.vaadin.flow.component.AttachEvent;
+import com.vaadin.flow.component.Focusable;
+import com.vaadin.flow.component.HasHelper;
+import com.vaadin.flow.component.HasLabel;
+import com.vaadin.flow.component.HasSize;
+import com.vaadin.flow.component.KeyNotifier;
+import com.vaadin.flow.component.UI;
+import com.vaadin.flow.component.shared.HasValidationProperties;
+import com.vaadin.flow.function.SerializableBiFunction;
+import com.vaadin.flow.function.SerializableRunnable;
+
+/**
+ * Abstract base class for slider components.
+ *
+ * @param
+ * the component type
+ * @param
+ * the value type
+ *
+ * @author Vaadin Ltd
+ */
+public abstract class SliderBase, TValue>
+ extends AbstractSinglePropertyField
+ implements HasLabel, HasHelper, HasValidationProperties, HasSize,
+ Focusable, KeyNotifier {
+ private Set pendingBeforeClientResponseActions = new HashSet<>();
+
+ /**
+ * Constructs a slider with the given min, max, step, initial value, and
+ * custom converters for the value property.
+ *
+ * @param
+ * the presentation type used by the element property
+ * @param min
+ * the minimum value
+ * @param max
+ * the maximum value
+ * @param step
+ * the step value
+ * @param value
+ * the initial value
+ * @param presentationType
+ * the class of the presentation type
+ * @param presentationToModel
+ * a function to convert from presentation to model
+ * @param modelToPresentation
+ * a function to convert from model to presentation
+ */
+ SliderBase(double min, double max, double step,
+ TValue value, Class presentationType,
+ SerializableBiFunction presentationToModel,
+ SerializableBiFunction modelToPresentation) {
+ super("value", null, presentationType, presentationToModel,
+ modelToPresentation);
+
+ getElement().setProperty("manualValidation", true);
+
+ setMinDouble(min);
+ setMaxDouble(max);
+ setStepDouble(step);
+ setValue(value);
+
+ // workaround for // https://github.com/vaadin/flow/issues/3496
+ setInvalid(false);
+ }
+
+ @Override
+ protected void onAttach(AttachEvent attachEvent) {
+ super.onAttach(attachEvent);
+ checkFeatureFlag(attachEvent.getUI());
+ }
+
+ private void checkFeatureFlag(UI ui) {
+ FeatureFlags featureFlags = FeatureFlags
+ .get(ui.getSession().getService().getContext());
+ boolean enabled = featureFlags
+ .isEnabled(SliderFeatureFlagProvider.SLIDER_COMPONENT);
+
+ if (!enabled) {
+ throw new ExperimentalFeatureException();
+ }
+ }
+
+ /**
+ * Sets the minimum value of the slider.
+ *
+ * @param min
+ * the minimum value
+ * @throws IllegalArgumentException
+ * if the min is greater than the max value
+ */
+ void setMinDouble(double min) {
+ if (min > getMaxDouble()) {
+ throw new IllegalArgumentException(
+ "The min value cannot be greater than the max value");
+ }
+
+ getElement().setProperty("min", min);
+ }
+
+ /**
+ * Gets the minimum value of the slider.
+ *
+ * @return the minimum value
+ */
+ double getMinDouble() {
+ return getElement().getProperty("min", 0);
+ }
+
+ /**
+ * Sets the maximum value of the slider.
+ *
+ * @param max
+ * the maximum value
+ * @throws IllegalArgumentException
+ * if the max is less than the min value
+ */
+ void setMaxDouble(double max) {
+ if (max < getMinDouble()) {
+ throw new IllegalArgumentException(
+ "The max value cannot be less than the min value");
+ }
+
+ getElement().setProperty("max", max);
+ }
+
+ /**
+ * Gets the maximum value of the slider.
+ *
+ * @return the maximum value
+ */
+ double getMaxDouble() {
+ return getElement().getProperty("max", 100);
+ }
+
+ /**
+ * Sets the step value of the slider. The step is the amount the value
+ * changes when the user moves the handle.
+ *
+ * @param step
+ * the step value
+ * @throws IllegalArgumentException
+ * if the step is less than or equal to zero
+ */
+ void setStepDouble(double step) {
+ if (step <= 0) {
+ throw new IllegalArgumentException(
+ "The step value must be a positive number");
+ }
+
+ getElement().setProperty("step", step);
+ }
+
+ /**
+ * Gets the step value of the slider.
+ *
+ * @return the step value
+ */
+ double getStepDouble() {
+ return getElement().getProperty("step", 1);
+ }
+
+ /**
+ * Schedules the given action to be executed before the client response,
+ * identified by the given key. If an action with the same key is already
+ * scheduled, it will not be added again.
+ *
+ * @param key
+ * the unique key identifying the action
+ * @param action
+ * the action to be executed
+ */
+ void scheduleBeforeClientResponse(String key, SerializableRunnable action) {
+ if (pendingBeforeClientResponseActions.contains(key)) {
+ return;
+ }
+
+ getElement().getNode().runWhenAttached(ui -> {
+ ui.beforeClientResponse(this, context -> {
+ pendingBeforeClientResponseActions.remove(key);
+ action.run();
+ });
+ });
+
+ pendingBeforeClientResponseActions.add(key);
+ }
+}
diff --git a/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/java/com/vaadin/flow/component/slider/SliderFeatureFlagProvider.java b/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/java/com/vaadin/flow/component/slider/SliderFeatureFlagProvider.java
new file mode 100644
index 00000000000..16e922e0545
--- /dev/null
+++ b/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/java/com/vaadin/flow/component/slider/SliderFeatureFlagProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2026 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.flow.component.slider;
+
+import java.util.List;
+
+import com.vaadin.experimental.Feature;
+import com.vaadin.experimental.FeatureFlagProvider;
+
+public class SliderFeatureFlagProvider implements FeatureFlagProvider {
+
+ public static final Feature SLIDER_COMPONENT = new Feature(
+ "Slider component", "sliderComponent",
+ "https://github.com/vaadin/platform/issues/8397", true,
+ "com.vaadin.flow.component.slider.Slider");
+
+ @Override
+ public List getFeatures() {
+ return List.of(SLIDER_COMPONENT);
+ }
+}
diff --git a/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/resources/META-INF/services/com.vaadin.experimental.FeatureFlagProvider b/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/resources/META-INF/services/com.vaadin.experimental.FeatureFlagProvider
new file mode 100644
index 00000000000..809a40f2baf
--- /dev/null
+++ b/vaadin-slider-flow-parent/vaadin-slider-flow/src/main/resources/META-INF/services/com.vaadin.experimental.FeatureFlagProvider
@@ -0,0 +1 @@
+com.vaadin.flow.component.slider.SliderFeatureFlagProvider
diff --git a/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/tests/RangeSliderSerializableTest.java b/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/tests/RangeSliderSerializableTest.java
new file mode 100644
index 00000000000..303fd71c45b
--- /dev/null
+++ b/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/tests/RangeSliderSerializableTest.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2000-2026 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.flow.component.slider.tests;
+
+import com.vaadin.flow.testutil.ClassesSerializableTest;
+
+public class RangeSliderSerializableTest extends ClassesSerializableTest {
+}
diff --git a/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/tests/RangeSliderTest.java b/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/tests/RangeSliderTest.java
new file mode 100644
index 00000000000..29ee039aaf6
--- /dev/null
+++ b/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/tests/RangeSliderTest.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2000-2026 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.flow.component.slider.tests;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.flow.component.Focusable;
+import com.vaadin.flow.component.HasSize;
+import com.vaadin.flow.component.KeyNotifier;
+import com.vaadin.flow.component.slider.RangeSlider;
+import com.vaadin.flow.component.slider.RangeSliderValue;
+
+public class RangeSliderTest {
+
+ @Test
+ public void defaultConstructor() {
+ RangeSlider slider = new RangeSlider();
+ Assert.assertEquals(0.0, slider.getMin(), 0.0);
+ Assert.assertEquals(100.0, slider.getMax(), 0.0);
+ Assert.assertEquals(1.0, slider.getStep(), 0.0);
+ Assert.assertEquals(new RangeSliderValue(0.0, 100.0),
+ slider.getValue());
+ }
+
+ @Test
+ public void listenerConstructor() {
+ AtomicBoolean listenerInvoked = new AtomicBoolean(false);
+ RangeSlider slider = new RangeSlider(e -> listenerInvoked.set(true));
+ Assert.assertEquals(0.0, slider.getMin(), 0.0);
+ Assert.assertEquals(100.0, slider.getMax(), 0.0);
+ Assert.assertEquals(1.0, slider.getStep(), 0.0);
+ Assert.assertEquals(new RangeSliderValue(0.0, 100.0),
+ slider.getValue());
+
+ slider.setValue(new RangeSliderValue(25.0, 75.0));
+ Assert.assertTrue(listenerInvoked.get());
+ }
+
+ @Test
+ public void minMaxValueConstructor() {
+ RangeSlider slider = new RangeSlider(10.0, 50.0,
+ new RangeSliderValue(15.0, 45.0));
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(1.0, slider.getStep(), 0.0);
+ Assert.assertEquals(new RangeSliderValue(15.0, 45.0),
+ slider.getValue());
+ }
+
+ @Test
+ public void minMaxValueListenerConstructor() {
+ AtomicBoolean listenerInvoked = new AtomicBoolean(false);
+ RangeSlider slider = new RangeSlider(10.0, 50.0,
+ new RangeSliderValue(15.0, 45.0),
+ e -> listenerInvoked.set(true));
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(1.0, slider.getStep(), 0.0);
+ Assert.assertEquals(new RangeSliderValue(15.0, 45.0),
+ slider.getValue());
+
+ slider.setValue(new RangeSliderValue(20.0, 40.0));
+ Assert.assertTrue(listenerInvoked.get());
+ }
+
+ @Test
+ public void minMaxStepValueConstructor() {
+ RangeSlider slider = new RangeSlider(10.0, 50.0, 5.0,
+ new RangeSliderValue(15.0, 45.0));
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(5.0, slider.getStep(), 0.0);
+ Assert.assertEquals(new RangeSliderValue(15.0, 45.0),
+ slider.getValue());
+ }
+
+ @Test
+ public void minMaxStepValueListenerConstructor() {
+ AtomicBoolean listenerInvoked = new AtomicBoolean(false);
+ RangeSlider slider = new RangeSlider(10.0, 50.0, 5.0,
+ new RangeSliderValue(15.0, 45.0),
+ e -> listenerInvoked.set(true));
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(5.0, slider.getStep(), 0.0);
+ Assert.assertEquals(new RangeSliderValue(15.0, 45.0),
+ slider.getValue());
+
+ slider.setValue(new RangeSliderValue(20.0, 40.0));
+ Assert.assertTrue(listenerInvoked.get());
+ }
+
+ @Test
+ public void labelConstructor() {
+ RangeSlider slider = new RangeSlider("Label");
+ Assert.assertEquals("Label", slider.getLabel());
+ Assert.assertEquals(0.0, slider.getMin(), 0.0);
+ Assert.assertEquals(100.0, slider.getMax(), 0.0);
+ Assert.assertEquals(1.0, slider.getStep(), 0.0);
+ Assert.assertEquals(new RangeSliderValue(0.0, 100.0),
+ slider.getValue());
+ }
+
+ @Test
+ public void labelListenerConstructor() {
+ AtomicBoolean listenerInvoked = new AtomicBoolean(false);
+ RangeSlider slider = new RangeSlider("Label",
+ e -> listenerInvoked.set(true));
+ Assert.assertEquals("Label", slider.getLabel());
+ Assert.assertEquals(0.0, slider.getMin(), 0.0);
+ Assert.assertEquals(100.0, slider.getMax(), 0.0);
+ Assert.assertEquals(1.0, slider.getStep(), 0.0);
+ Assert.assertEquals(new RangeSliderValue(0.0, 100.0),
+ slider.getValue());
+
+ slider.setValue(new RangeSliderValue(25.0, 75.0));
+ Assert.assertTrue(listenerInvoked.get());
+ }
+
+ @Test
+ public void labelMinMaxValueConstructor() {
+ RangeSlider slider = new RangeSlider("Label", 10.0, 50.0,
+ new RangeSliderValue(15.0, 45.0));
+ Assert.assertEquals("Label", slider.getLabel());
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(1.0, slider.getStep(), 0.0);
+ Assert.assertEquals(new RangeSliderValue(15.0, 45.0),
+ slider.getValue());
+ }
+
+ @Test
+ public void labelMinMaxValueListenerConstructor() {
+ AtomicBoolean listenerInvoked = new AtomicBoolean(false);
+ RangeSlider slider = new RangeSlider("Label", 10.0, 50.0,
+ new RangeSliderValue(15.0, 45.0),
+ e -> listenerInvoked.set(true));
+ Assert.assertEquals("Label", slider.getLabel());
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(1.0, slider.getStep(), 0.0);
+ Assert.assertEquals(new RangeSliderValue(15.0, 45.0),
+ slider.getValue());
+
+ slider.setValue(new RangeSliderValue(20.0, 40.0));
+ Assert.assertTrue(listenerInvoked.get());
+ }
+
+ @Test
+ public void labelMinMaxStepValueConstructor() {
+ RangeSlider slider = new RangeSlider("Label", 10.0, 50.0, 5.0,
+ new RangeSliderValue(15.0, 45.0));
+ Assert.assertEquals("Label", slider.getLabel());
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(5.0, slider.getStep(), 0.0);
+ Assert.assertEquals(new RangeSliderValue(15.0, 45.0),
+ slider.getValue());
+ }
+
+ @Test
+ public void labelMinMaxStepValueListenerConstructor() {
+ AtomicBoolean listenerInvoked = new AtomicBoolean(false);
+ RangeSlider slider = new RangeSlider("Label", 10.0, 50.0, 5.0,
+ new RangeSliderValue(15.0, 45.0),
+ e -> listenerInvoked.set(true));
+ Assert.assertEquals("Label", slider.getLabel());
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(5.0, slider.getStep(), 0.0);
+ Assert.assertEquals(new RangeSliderValue(15.0, 45.0),
+ slider.getValue());
+
+ slider.setValue(new RangeSliderValue(20.0, 40.0));
+ Assert.assertTrue(listenerInvoked.get());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void setValue_startLessThanMin_throws() {
+ RangeSlider slider = new RangeSlider(0.0, 100.0, 1.0,
+ new RangeSliderValue(0.0, 100.0));
+ slider.setValue(new RangeSliderValue(-10.0, 50.0));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void setValue_endGreaterThanMax_throws() {
+ RangeSlider slider = new RangeSlider(0.0, 100.0, 1.0,
+ new RangeSliderValue(0.0, 100.0));
+ slider.setValue(new RangeSliderValue(50.0, 150.0));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void setValue_startGreaterThanEnd_throws() {
+ new RangeSliderValue(75.0, 25.0);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void setValue_null_throws() {
+ RangeSlider slider = new RangeSlider();
+ slider.setValue(null);
+ }
+
+ @Test
+ public void implementsHasSizeInterface() {
+ RangeSlider slider = new RangeSlider();
+ Assert.assertTrue(slider instanceof HasSize);
+ }
+
+ @Test
+ public void implementsFocusableInterface() {
+ RangeSlider slider = new RangeSlider();
+ Assert.assertTrue(slider instanceof Focusable);
+ }
+
+ @Test
+ public void implementsKeyNotifierInterface() {
+ RangeSlider slider = new RangeSlider();
+ Assert.assertTrue(slider instanceof KeyNotifier);
+ }
+
+ @Test
+ public void setMin_getMin() {
+ RangeSlider slider = new RangeSlider(0.0, 100.0, 1.0,
+ new RangeSliderValue(0.0, 100.0));
+ Assert.assertEquals(0.0, slider.getMin(), 0.0);
+ Assert.assertEquals(0.0, slider.getElement().getProperty("min", 0.0),
+ 0.0);
+
+ slider.setMin(-10.0);
+ Assert.assertEquals(-10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(-10.0, slider.getElement().getProperty("min", 0.0),
+ 0.0);
+ }
+
+ @Test
+ public void setMax_getMax() {
+ RangeSlider slider = new RangeSlider(0.0, 100.0, 1.0,
+ new RangeSliderValue(0.0, 100.0));
+ Assert.assertEquals(100.0, slider.getMax(), 0.0);
+ Assert.assertEquals(100.0, slider.getElement().getProperty("max", 0.0),
+ 0.0);
+
+ slider.setMax(200.0);
+ Assert.assertEquals(200.0, slider.getMax(), 0.0);
+ Assert.assertEquals(200.0, slider.getElement().getProperty("max", 0.0),
+ 0.0);
+ }
+
+ @Test
+ public void setStep_getStep() {
+ RangeSlider slider = new RangeSlider(0.0, 100.0, 1.0,
+ new RangeSliderValue(0.0, 100.0));
+ Assert.assertEquals(1.0, slider.getStep(), 0.0);
+ Assert.assertEquals(1.0, slider.getElement().getProperty("step", 1.0),
+ 0.0);
+
+ slider.setStep(5.0);
+ Assert.assertEquals(5.0, slider.getStep(), 0.0);
+ Assert.assertEquals(5.0, slider.getElement().getProperty("step", 1.0),
+ 0.0);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void setMin_greaterThanMax_throws() {
+ RangeSlider slider = new RangeSlider(0.0, 100.0, 1.0,
+ new RangeSliderValue(0.0, 100.0));
+ slider.setMin(150.0);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void setMax_lessThanMin_throws() {
+ RangeSlider slider = new RangeSlider(50.0, 100.0, 10.0,
+ new RangeSliderValue(50.0, 100.0));
+ slider.setMax(25.0);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void setStep_notPositive_throws() {
+ RangeSlider slider = new RangeSlider(0.0, 100.0, 1.0,
+ new RangeSliderValue(0.0, 100.0));
+ slider.setStep(0.0);
+ }
+}
diff --git a/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/tests/SliderSerializableTest.java b/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/tests/SliderSerializableTest.java
new file mode 100644
index 00000000000..0e628b3d9a4
--- /dev/null
+++ b/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/tests/SliderSerializableTest.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2000-2026 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.flow.component.slider.tests;
+
+import com.vaadin.flow.testutil.ClassesSerializableTest;
+
+public class SliderSerializableTest extends ClassesSerializableTest {
+}
diff --git a/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/tests/SliderTest.java b/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/tests/SliderTest.java
new file mode 100644
index 00000000000..96d74c7cede
--- /dev/null
+++ b/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/tests/SliderTest.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2000-2026 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.flow.component.slider.tests;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.flow.component.Focusable;
+import com.vaadin.flow.component.HasSize;
+import com.vaadin.flow.component.KeyNotifier;
+import com.vaadin.flow.component.slider.Slider;
+
+public class SliderTest {
+ @Test
+ public void defaultConstructor() {
+ Slider slider = new Slider();
+ Assert.assertEquals(0.0, slider.getMin(), 0.0);
+ Assert.assertEquals(100.0, slider.getMax(), 0.0);
+ Assert.assertEquals(0.0, slider.getValue(), 0.0);
+ }
+
+ @Test
+ public void listenerConstructor() {
+ AtomicBoolean listenerInvoked = new AtomicBoolean(false);
+ Slider slider = new Slider(e -> listenerInvoked.set(true));
+ Assert.assertEquals(0.0, slider.getMin(), 0.0);
+ Assert.assertEquals(100.0, slider.getMax(), 0.0);
+ Assert.assertEquals(0.0, slider.getValue(), 0.0);
+
+ slider.setValue(50.0);
+ Assert.assertTrue(listenerInvoked.get());
+ }
+
+ @Test
+ public void minMaxValueConstructor() {
+ Slider slider = new Slider(10.0, 50.0, 25.0);
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(1.0, slider.getStep(), 0.0);
+ Assert.assertEquals(25.0, slider.getValue(), 0.0);
+ }
+
+ @Test
+ public void minMaxValueListenerConstructor() {
+ AtomicBoolean listenerInvoked = new AtomicBoolean(false);
+ Slider slider = new Slider(10.0, 50.0, 25.0,
+ e -> listenerInvoked.set(true));
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(1.0, slider.getStep(), 0.0);
+ Assert.assertEquals(25.0, slider.getValue(), 0.0);
+
+ slider.setValue(30.0);
+ Assert.assertTrue(listenerInvoked.get());
+ }
+
+ @Test
+ public void minMaxStepValueConstructor() {
+ Slider slider = new Slider(10.0, 50.0, 5.0, 25.0);
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(5.0, slider.getStep(), 0.0);
+ Assert.assertEquals(25.0, slider.getValue(), 0.0);
+ }
+
+ @Test
+ public void minMaxStepValueListenerConstructor() {
+ AtomicBoolean listenerInvoked = new AtomicBoolean(false);
+ Slider slider = new Slider(10.0, 50.0, 5.0, 25.0,
+ e -> listenerInvoked.set(true));
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(5.0, slider.getStep(), 0.0);
+ Assert.assertEquals(25.0, slider.getValue(), 0.0);
+
+ slider.setValue(30.0);
+ Assert.assertTrue(listenerInvoked.get());
+ }
+
+ @Test
+ public void labelConstructor() {
+ Slider slider = new Slider("Label");
+ Assert.assertEquals("Label", slider.getLabel());
+ Assert.assertEquals(0.0, slider.getMin(), 0.0);
+ Assert.assertEquals(100.0, slider.getMax(), 0.0);
+ Assert.assertEquals(0.0, slider.getValue(), 0.0);
+ }
+
+ @Test
+ public void labelListenerConstructor() {
+ AtomicBoolean listenerInvoked = new AtomicBoolean(false);
+ Slider slider = new Slider("Label", e -> listenerInvoked.set(true));
+ Assert.assertEquals("Label", slider.getLabel());
+ Assert.assertEquals(0.0, slider.getMin(), 0.0);
+ Assert.assertEquals(100.0, slider.getMax(), 0.0);
+ Assert.assertEquals(0.0, slider.getValue(), 0.0);
+
+ slider.setValue(50.0);
+ Assert.assertTrue(listenerInvoked.get());
+ }
+
+ @Test
+ public void labelMinMaxValueConstructor() {
+ Slider slider = new Slider("Label", 10.0, 50.0, 25.0);
+ Assert.assertEquals("Label", slider.getLabel());
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(1.0, slider.getStep(), 0.0);
+ Assert.assertEquals(25.0, slider.getValue(), 0.0);
+ }
+
+ @Test
+ public void labelMinMaxValueListenerConstructor() {
+ AtomicBoolean listenerInvoked = new AtomicBoolean(false);
+ Slider slider = new Slider("Label", 10.0, 50.0, 25.0,
+ e -> listenerInvoked.set(true));
+ Assert.assertEquals("Label", slider.getLabel());
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(1.0, slider.getStep(), 0.0);
+ Assert.assertEquals(25.0, slider.getValue(), 0.0);
+
+ slider.setValue(30.0);
+ Assert.assertTrue(listenerInvoked.get());
+ }
+
+ @Test
+ public void labelMinMaxStepValueConstructor() {
+ Slider slider = new Slider("Label", 10.0, 50.0, 5.0, 25.0);
+ Assert.assertEquals("Label", slider.getLabel());
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(5.0, slider.getStep(), 0.0);
+ Assert.assertEquals(25.0, slider.getValue(), 0.0);
+ }
+
+ @Test
+ public void labelMinMaxStepValueListenerConstructor() {
+ AtomicBoolean listenerInvoked = new AtomicBoolean(false);
+ Slider slider = new Slider("Label", 10.0, 50.0, 5.0, 25.0,
+ e -> listenerInvoked.set(true));
+ Assert.assertEquals("Label", slider.getLabel());
+ Assert.assertEquals(10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(50.0, slider.getMax(), 0.0);
+ Assert.assertEquals(5.0, slider.getStep(), 0.0);
+ Assert.assertEquals(25.0, slider.getValue(), 0.0);
+
+ slider.setValue(30.0);
+ Assert.assertTrue(listenerInvoked.get());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void setValue_lessThanMin_throws() {
+ Slider slider = new Slider(0.0, 100.0, 1.0, 0.0);
+ slider.setValue(-150.0);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void setValue_greaterThanMax_throws() {
+ Slider slider = new Slider(0.0, 100.0, 1.0, 0.0);
+ slider.setValue(150.0);
+ }
+
+ public void implementsHasSizeInterface() {
+ Slider slider = new Slider();
+ Assert.assertTrue(slider instanceof HasSize);
+ }
+
+ public void implementsFocusableInterface() {
+ Slider slider = new Slider();
+ Assert.assertTrue(slider instanceof Focusable);
+ }
+
+ public void implementsKeyNotifierInterface() {
+ Slider slider = new Slider();
+ Assert.assertTrue(slider instanceof KeyNotifier);
+ }
+
+ @Test
+ public void setMin_getMin() {
+ Slider slider = new Slider(0.0, 100.0, 1.0, 0.0);
+ Assert.assertEquals(0.0, slider.getMin(), 0.0);
+ Assert.assertEquals(0.0, slider.getElement().getProperty("min", 0.0),
+ 0.0);
+
+ slider.setMin(-10.0);
+ Assert.assertEquals(-10.0, slider.getMin(), 0.0);
+ Assert.assertEquals(-10.0, slider.getElement().getProperty("min", 0.0),
+ 0.0);
+ }
+
+ @Test
+ public void setMax_getMax() {
+ Slider slider = new Slider(0.0, 100.0, 1.0, 0.0);
+ Assert.assertEquals(100.0, slider.getMax(), 0.0);
+ Assert.assertEquals(100.0, slider.getElement().getProperty("max", 0.0),
+ 0.0);
+
+ slider.setMax(200.0);
+ Assert.assertEquals(200.0, slider.getMax(), 0.0);
+ Assert.assertEquals(200.0, slider.getElement().getProperty("max", 0.0),
+ 0.0);
+ }
+
+ @Test
+ public void setStep_getStep() {
+ Slider slider = new Slider(0.0, 100.0, 1.0, 0.0);
+ Assert.assertEquals(1.0, slider.getStep(), 0.0);
+ Assert.assertEquals(1.0, slider.getElement().getProperty("step", 1.0),
+ 0.0);
+
+ slider.setStep(5.0);
+ Assert.assertEquals(5.0, slider.getStep(), 0.0);
+ Assert.assertEquals(5.0, slider.getElement().getProperty("step", 1.0),
+ 0.0);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void setMin_greaterThanMax_throws() {
+ Slider slider = new Slider(0.0, 100.0, 1.0, 0.0);
+ slider.setMin(150.0);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void setMax_lessThanMin_throws() {
+ Slider slider = new Slider(50.0, 100.0, 10.0, 50.0);
+ slider.setMax(25.0);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void setStep_notPositive_throws() {
+ Slider slider = new Slider(0.0, 100.0, 1.0, 0.0);
+ slider.setStep(0.0);
+ }
+}
diff --git a/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/validation/SliderBasicValidationTest.java b/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/validation/SliderBasicValidationTest.java
new file mode 100644
index 00000000000..8d507cfa22a
--- /dev/null
+++ b/vaadin-slider-flow-parent/vaadin-slider-flow/src/test/java/com/vaadin/flow/component/slider/validation/SliderBasicValidationTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2026 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.flow.component.slider.validation;
+
+import com.vaadin.flow.component.slider.Slider;
+import com.vaadin.tests.validation.AbstractBasicValidationTest;
+
+public class SliderBasicValidationTest
+ extends AbstractBasicValidationTest {
+
+ @Override
+ protected Slider createTestField() {
+ return new Slider();
+ }
+}
diff --git a/vaadin-slider-flow-parent/vaadin-slider-testbench/pom.xml b/vaadin-slider-flow-parent/vaadin-slider-testbench/pom.xml
new file mode 100644
index 00000000000..03f35c68820
--- /dev/null
+++ b/vaadin-slider-flow-parent/vaadin-slider-testbench/pom.xml
@@ -0,0 +1,45 @@
+
+
+ 4.0.0
+
+ com.vaadin
+ vaadin-slider-flow-parent
+ 25.1-SNAPSHOT
+
+ vaadin-slider-testbench
+ jar
+ Vaadin Slider Testbench API
+ Vaadin Slider Testbench API
+
+
+ com.vaadin
+ vaadin-testbench-shared
+ provided
+
+
+
+
+
+
+
+ attach-docs
+
+
+ with-docs
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+
+
+
+
diff --git a/vaadin-slider-flow-parent/vaadin-slider-testbench/src/main/java/com/vaadin/flow/component/slider/testbench/RangeSliderElement.java b/vaadin-slider-flow-parent/vaadin-slider-testbench/src/main/java/com/vaadin/flow/component/slider/testbench/RangeSliderElement.java
new file mode 100644
index 00000000000..441eea2c1e2
--- /dev/null
+++ b/vaadin-slider-flow-parent/vaadin-slider-testbench/src/main/java/com/vaadin/flow/component/slider/testbench/RangeSliderElement.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2026 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.flow.component.slider.testbench;
+
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.testbench.elementsbase.Element;
+
+/**
+ * A TestBench element representing a <vaadin-range-slider>
+ * element.
+ */
+@Element("vaadin-range-slider")
+public class RangeSliderElement extends TestBenchElement {
+
+ /**
+ * Gets the start value of the range slider.
+ *
+ * @return the start value
+ */
+ public double getStartValue() {
+ return getPropertyDouble("value", "0");
+ }
+
+ /**
+ * Gets the end value of the range slider.
+ *
+ * @return the end value
+ */
+ public double getEndValue() {
+ return getPropertyDouble("value", "1");
+ }
+
+ /**
+ * Gets the minimum value of the range slider.
+ *
+ * @return the minimum value
+ */
+ public double getMin() {
+ return getPropertyDouble("min");
+ }
+
+ /**
+ * Gets the maximum value of the range slider.
+ *
+ * @return the maximum value
+ */
+ public double getMax() {
+ return getPropertyDouble("max");
+ }
+
+ /**
+ * Gets the step value of the range slider.
+ *
+ * @return the step value
+ */
+ public double getStep() {
+ return getPropertyDouble("step");
+ }
+}
diff --git a/vaadin-slider-flow-parent/vaadin-slider-testbench/src/main/java/com/vaadin/flow/component/slider/testbench/SliderElement.java b/vaadin-slider-flow-parent/vaadin-slider-testbench/src/main/java/com/vaadin/flow/component/slider/testbench/SliderElement.java
new file mode 100644
index 00000000000..9b36c1111c8
--- /dev/null
+++ b/vaadin-slider-flow-parent/vaadin-slider-testbench/src/main/java/com/vaadin/flow/component/slider/testbench/SliderElement.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2026 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.flow.component.slider.testbench;
+
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.testbench.elementsbase.Element;
+
+/**
+ * A TestBench element representing a <vaadin-slider>
+ * element.
+ */
+@Element("vaadin-slider")
+public class SliderElement extends TestBenchElement {
+
+ /**
+ * Gets the current value of the slider.
+ *
+ * @return the current value
+ */
+ public double getValue() {
+ return getPropertyDouble("value");
+ }
+
+ /**
+ * Gets the minimum value of the slider.
+ *
+ * @return the minimum value
+ */
+ public double getMin() {
+ return getPropertyDouble("min");
+ }
+
+ /**
+ * Gets the maximum value of the slider.
+ *
+ * @return the maximum value
+ */
+ public double getMax() {
+ return getPropertyDouble("max");
+ }
+
+ /**
+ * Gets the step value of the slider.
+ *
+ * @return the step value
+ */
+ public double getStep() {
+ return getPropertyDouble("step");
+ }
+}