<script setup lang="ts">
import { ASliderRange, ASliderRoot, ASliderThumb, ASliderTrack } from 'akar';
import { ref } from 'vue';
const value = ref([50]);
</script>
<template>
<ASliderRoot
v-model="value"
class="flex w-full select-none items-center relative touch-none"
:max="100"
:step="1"
>
<ASliderTrack class="rounded-full bg-background-accented grow h-[8px] relative overflow-hidden">
<ASliderRange class="rounded-full bg-primary h-full absolute" />
</ASliderTrack>
<ASliderThumb
class="rounded-full bg-background size-4 ring-2 ring-primary focus-visible:(outline-2 outline-primary/50 outline-offset-2)"
aria-label="Volume"
/>
</ASliderRoot>
</template>
Import all parts and piece them together.
<script setup>
import { ASliderRange, ASliderRoot, ASliderThumb, ASliderTrack } from 'akar';
</script>
<template>
<ASliderRoot>
<ASliderTrack>
<ASliderRange />
</ASliderTrack>
<ASliderThumb />
</ASliderRoot>
</template>
One benefit of using Akar is its flexibility and low-level control over the components. However, this also means that you may need to manually construct more complex UI elements by combining multiple Akar components together.
If you feel there's a lot of elements that needs to be constructed manually using Akar, consider using Pohon UI instead. It provides a higher-level abstraction over Akar components with pre-defined styles and behaviors that can help you build UIs faster.
Contains all the parts of a slider. It will render an input for each thumb when used within a form to ensure events propagate correctly.
| Prop | Default | Type |
|---|---|---|
as | 'span' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
defaultValue | [0] | number[]The value of the slider when initially rendered. Use when you do not need to control the state of the slider. |
dir | 'ltr' | 'rtl'The reading direction of the combobox when applicable. | |
disabled | false | booleanWhen |
inverted | false | booleanWhether the slider is visually inverted. |
max | 100 | numberThe maximum value for the range. |
min | 0 | numberThe minimum value for the range. |
minStepsBetweenThumbs | 0 | numberThe minimum permitted steps between multiple thumbs. |
modelValue | number[] | null | |
name | stringThe name of the field. Submitted with its owning form as part of a name/value pair. | |
orientation | 'horizontal' | 'horizontal' | 'vertical'The orientation of the slider. |
required | booleanWhen | |
step | 1 | numberThe stepping interval. |
thumbAlignment | 'contain' | 'contain' | 'overflow'The alignment of the slider thumb.
|
| Event | Type |
|---|---|
update:modelValue | [payload: number[]]Event handler called when the slider value changes |
valueCommit | [payload: number[]]Event handler called when the value changes at the end of an interaction. |
| Slot | Type |
|---|---|
modelValue | number[] | nullThe controlled value of the slider. Can be bind as |
| Attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
[data-orientation] | 'vertical' | 'horizontal' |
The track that contains the ASliderRange.
| Prop | Default | Type |
|---|---|---|
as | 'span' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
| Attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
[data-orientation] | 'vertical' | 'horizontal' |
The range part. Must live inside ASliderTrack.
| Prop | Default | Type |
|---|---|---|
as | 'span' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
| Attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
[data-orientation] | 'vertical' | 'horizontal' |
A draggable thumb. You can render multiple thumbs.
| Prop | Default | Type |
|---|---|---|
as | 'span' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
| Attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
[data-orientation] | 'vertical' | 'horizontal' |
Use the orientation prop to create a vertical slider.
// index.vue
<script setup>
import { ASliderRange, ASliderRoot, ASliderThumb, ASliderTrack } from 'akar';
</script>
<template>
<ASliderRoot
class="ASliderRoot"
:default-value="[50]"
orientation="vertical"
>
<ASliderTrack class="ASliderTrack">
<ASliderRange class="ASliderRange" />
</ASliderTrack>
<ASliderThumb class="ASliderThumb" />
</ASliderRoot>
</template>
/* styles.css */
.ASliderRoot {
position: relative;
display: flex;
align-items: center;
}
.ASliderRoot[data-orientation='vertical'] {
flex-direction: column;
width: 20px;
height: 100px;
}
.ASliderTrack {
position: relative;
flex-grow: 1;
background-color: grey;
}
.ASliderTrack[data-orientation='vertical'] {
width: 3px;
}
.ASliderRange {
position: absolute;
background-color: black;
}
.ASliderRange[data-orientation='vertical'] {
width: 100%;
}
.ASliderThumb {
display: block;
width: 20px;
height: 20px;
background-color: black;
}
Add multiple thumbs and values to create a range slider.
// index.vue
<script setup>
import { ASliderRange, ASliderRoot, ASliderThumb, ASliderTrack } from 'akar';
</script>
<template>
<ASliderRoot :default-value="[25, 75]">
<ASliderTrack>
<ASliderRange />
</ASliderTrack>
<ASliderThumb />
<ASliderThumb />
</ASliderRoot>
</template>
Use the step prop to increase the stepping interval.
// index.vue
<script setup>
import { ASliderRange, ASliderRoot, ASliderThumb, ASliderTrack } from 'akar';
</script>
<template>
<ASliderRoot
:default-value="[50]"
:step="10"
>
<ASliderTrack>
<ASliderRange />
</ASliderTrack>
<ASliderThumb />
</ASliderRoot>
</template>
Use minStepsBetweenThumbs to avoid thumbs with equal values.
// index.vue
<script setup>
import { ASliderRange, ASliderRoot, ASliderThumb, ASliderTrack } from 'akar';
</script>
<template>
<ASliderRoot
:default-value="[25, 75]"
:step="10"
:min-steps-between-thumbs="1"
>
<ASliderTrack>
<ASliderRange />
</ASliderTrack>
<ASliderThumb />
<ASliderThumb />
</ASliderRoot>
</template>
Adheres to the ASlider WAI-ARIA design pattern.
| Key | Description |
|---|---|
ArrowRight | Increases the value by the |
ArrowLeft | Decreases the value by the |
ArrowUp | Increases the value by the |
ArrowDown | Decreases the value by the |
PageUp | Increases the value by a larger |
PageDown | Decreases the value by a larger |
Shift + ArrowUp | Increases the value by a larger |
Shift + ArrowDown | Decreases the value by a larger |
Home | Sets the value to its minimum. |
End | Sets the value to its maximum. |
When the slider is inverted, some controls are inverted as well, depending on the orientation.
horizontal (the default), ArrowRight, ArrowLeft, Home, and End are inverted.vertical, ArrowUp, ArrowDown, PageUp, PageDown, Shift + ArrowUp, and Shift + ArrowDown are inverted.Create your own API by abstracting the primitive parts into your own component.
This example abstracts all of the ASlider parts so it can be used as a self closing element.
<script setup lang="ts">
import { ASlider } from './your-slider';
</script>
<template>
<ASlider :default-value="[25]" />
</template>
// your-slider.ts
export { default as ASlider } from 'ASlider.vue';
<!-- ASlider.vue -->
<script setup lang="ts">
import type { ASliderRootEmits, ASliderRootProps } from 'akar';
import { ASliderRange, ASliderRoot, ASliderThumb, ASliderTrack, useForwardPropsEmits } from 'akar';
const props = defineProps<ASliderRootProps>();
const emits = defineEmits<ASliderRootEmits>();
const forward = useForwardPropsEmits(props, emits);
</script>
<template>
<ASliderRoot
v-slot="{ modelValue }"
v-bind="forward"
>
<ASliderTrack>
<ASliderRange />
</ASliderTrack>
<ASliderThumb
v-for="(_, i) in modelValue"
:key="i"
/>
</ASliderRoot>
</template>
Because of a limitation we faced during implementation, the following example won't work as expected and the @mousedown and @mousedown event handlers won't be fired:
<ASliderRoot
@mousedown="() => { console.log('onMouseDown') }"
@mouseup="() => { console.log('onMouseUp') }"
>
…
</ASliderRoot>
We recommend using pointer events instead (eg. @pointerdown, @pointerup). Regardless of the above limitation, these events are better suited for cross-platform/device handling as they are fired for all pointer input types (mouse, touch, pen, etc.).