Skip to content

Slider

A draggable input to control numeric values.

Props


  • 🎹 Keyboard navigation
  • 🧠 Smart focus management
  • 🔄 Horizontal and vertical orientation
  • 💬 Tooltip value display
  • 🌐 RTL support (incoming!)
<script lang="ts">
import { Slider, type SliderProps } from "melt/builders";
const slider = new Slider();
</script>
<div {...slider.root}>
<div {...slider.thumb}></div>
</div>

By default, Melt does not provide styles. This means that you’ll be responsible for positioning the thumb and range of your slider.

To facilitate this, Melt provides some CSS properties, --percentage and --percentage-inv.

<Slider value={30} {...controls}>
{#snippet children(slider)}
<div class="slider" {...slider.root}>
<div class="track">
<div class="range"></div>
<div {...slider.thumb}></div>
</div>
</div>
{/snippet}
</Slider>
<style>
.slider {
width: 300px;
height: 40px;
margin: 0 auto;
padding-block: 16px; /* padding to increase touch area */
}
.slider .track {
background: grey;
height: 100%;
position: relative;
}
.slider .range {
position: absolute;
background: green;
inset: 0;
right: var(--percentage-inv);
}
.slider [data-melt-slider-thumb] {
position: absolute;
background: white;
left: var(--percentage);
top: 50%;
transform: translate(-50%, -50%);
width: 20px;
height: 20px;
}
</style>

TODO: Write about data-dragging

Constructor Props

The props that are passed when calling
new Slider()
    export type SliderProps = {
    /**
    * The minimum value of the slider.
    *
    * @default 0
    */
    min?: MaybeGetter<number | undefined>;
    /**
    * The maximum value of the slider.
    *
    * @default 100
    */
    max?: MaybeGetter<number | undefined>;
    /**
    * The orientation of the slider.
    *
    * @default "horizontal"
    */
    orientation?: MaybeGetter<"horizontal" | "vertical" | undefined>;
    /**
    * The step size of the slider.
    *
    * @default 1
    */
    step?: MaybeGetter<number | undefined>;
    /**
    * The default value for `tabs.value`
    *
    * When passing a getter, it will be used as source of truth,
    * meaning that `tabs.value` only changes when the getter returns a new value.
    *
    * If omitted, it will use the first tab as default.
    *
    * @default undefined
    */
    value?: MaybeGetter<number | undefined>;
    /**
    * Called when the `Slider` instance tries to change the active tab.
    */
    onValueChange?: (active: number) => void;
    };

Properties

The properties returned from
new Slider()
  • min

    number
  • max

    number
  • orientation

    "horizontal" | "vertical"
  • step

    number
  • ids

    { root: string; thumb: string }
  • value

    number
    The value of the slider.
  • root

    {
    readonly "data-dragging": "" | undefined
    readonly "data-value": number
    readonly "data-orientation": "horizontal" | "vertical"
    readonly "aria-valuenow": number
    readonly "aria-valuemin": number
    readonly "aria-valuemax": number
    readonly "aria-orientation": "horizontal" | "vertical"
    readonly style: `--percentage: ${string}; --percentage-inv: ${string}; touch-action: ${string}`
    readonly tabindex: 0
    readonly role: "slider"
    readonly "data-melt-slider-root": ""
    readonly id: string
    readonly onpointerdown: (e: PointerEvent) => void
    readonly onkeydown: (e: KeyboardEvent) => void
    }
    The root of the slider. Any cursor interaction along this element will change the slider's values.
  • thumb

    {
    readonly "data-dragging": "" | undefined
    readonly "data-value": number
    readonly "data-orientation": "horizontal" | "vertical"
    readonly "data-melt-slider-thumb": ""
    readonly id: string
    readonly tabindex: 0
    }
    The slider's thumb, positioned at the end of the range.