This project is forked from Vueform Slider, which want to resolve the problem that aria-labels cannot be applied to slider handle separately.
Vueform is comprehensive form development framework for Vue.js. It supercharges and standardizes the entire form building process and takes care of everything from rendering to validation and processing. With our latest tool, the Drag and Drop Form Builder, you can allow your developers & non-tech workforce to build the most complex forms without coding.
Feature highlights:
- integrate Vueform Drag and Drop Form Builder into any application
- save forms in database as a JSON
- use your own form elements with custom configuration options
- a complete theming and templating system with Tailwind support
- 25+ form elements with multi-file uploads, date pickers and rich text editor
- element nesting and repeating
- 50+ validators with async, dependent and custom rules
- conditional logic on element & form level
- breaking forms into steps with form wizard
- translating form content and global i18n support.
Learn more:
- Builder: https://builder.vueform.com
- Framework: https://vueform.com
- @vueform/multiselect - Vue 3 multiselect component with single select, multiselect and tagging options.
- @vueform/toggle - Vue 3 toggle component with labels, custom slots and styling options.
- Vue 2 & 3 support
- 100% coverage
- TypeScript support
- ESM support
- Fully configurable
- Single slider
- Multiple sliders
- Tooltips
- Formatting
- CSS vars support
- Accessibility support
- Tailwind & utility class support
- Based on noUiSlider
Check out our demo.
npm install @vueform/slider
<template>
<div>
<Slider v-model="value" />
</div>
</template>
<script>
import Slider from '@vueform/slider'
export default {
components: {
Slider,
},
data() {
return {
value: 20
}
}
}
</script>
<style src="@vueform/slider/themes/default.css"></style>
<template>
<div>
<Slider v-model="value" />
</div>
</template>
<script>
import Slider from '@vueform/slider/dist/slider.vue2.js'
export default {
components: {
Slider,
},
data() {
return {
value: 20
}
}
}
</script>
<style src="@vueform/slider/themes/default.css"></style>
Switch to <= 2.0.10
to use the Slider with Vue.js < 2.7
.
Join our Discord channel or open an issue.
Name | Type | Default | Description |
---|---|---|---|
id | string |
slider |
The id attribute of slider container DOM. |
lazy | boolean |
true |
Whether to update v-model only when the slider value is set and not while dragging. If disabled you must not use inline objects as props (eg. format , options , classes ) but outsource them to a data property. |
disabled | boolean |
false |
Whether the slider should be disabled. |
min | number |
0 |
Minimum value of the slider. |
max | number |
100 |
Maximum value of the slider. |
step | number |
1 |
The jump between intervals. If -1 it enables fractions (eg. 1.23 ). |
tooltips | boolean |
true |
Whether tooltips should show above handlers. |
showTooltip | string |
'always' |
When tooltips should be shown. Possible values: always|focus|drag . |
merge | number |
-1 |
The step distance between two handles when their tooltips should be merged (when step is -1 then 1 is assumed). Eg: { merge: 5, step: 10 } -> values: 0, <=50 will merge -> values: 0, 60 will not merge { merge: 5, step: -1 } -> values: 0, <=5 will merge -> values: 0, 5.01 will not merge |
format | object|function |
Formats the tooltip. It can be either a function that receives a value param and expects a string or number as return or an object with the following properties: prefix - eg $ -> $100 suffix - eg USD -> 100USD decimals - eg 2 -> 100.00 thousand - eg , - 1,000 |
|
orientation | string |
'horizontal' |
The orientation of the slider. Possible values: horizontal|vertical |
direction | string |
'ltr' |
The direction of the slider. By default value increases left-to-right and top-to-bottom, which is reversed when using rtl . Possible values: ltr|rtl |
tooltipPosition | string |
null |
The position of the slider tooltips. Possible values: null|'top'|'bottom'|'left'|'right' depending on orientation prop. When null it equals to orientation default ('top' for 'horizontal' and 'left' for 'vertical' ). |
aria | object |
An object containing aria attributes to be added for each handle. | |
ariaLabelledby | string |
null |
Sets the aria-labelledby attribute of handles. |
options | object |
{} |
Additional options for noUiSlider. |
classes | object |
An object of class names that gets merged with the default values. Default:{ target: 'slider-target', ltr: 'slider-ltr', rtl: 'slider-rtl', horizontal: 'slider-horizontal', vertical: 'slider-vertical', textDirectionRtl: 'slider-txt-dir-rtl', textDirectionLtr: 'slider-txt-dir-ltr', base: 'slider-base', connects: 'slider-connects', connect: 'slider-connect', origin: 'slider-origin', handle: 'slider-handle', handleLower: 'slider-handle-lower', handleUpper: 'slider-handle-upper', touchArea: 'slider-touch-area', tooltip: 'slider-tooltip', tooltipTop: 'slider-tooltip-top', tooltipBottom: 'slider-tooltip-bottom', tooltipLeft: 'slider-tooltip-left', tooltipRight: 'slider-tooltip-right', active: 'slider-active', draggable: 'slider-draggable', tap: 'slider-state-tap', drag: 'slider-state-drag' } |
Event | Attributes | Description |
---|---|---|
@change | value |
Emitted when dragging the slider is finished or it's value changed by clicking, keyboard or programmatical set. |
@update | value |
Emitted in the same scenarios as in @change , but also when the slider is being dragged if lazy option is disabled. |
@set | value |
Emitted in the same scenarios as in @change , but also when the slider's .set() method is called. |
@slide | value |
Emitted while the slider moves. |
@drag | value |
Emitted the slider connect moves while dragging. |
@start | value |
Emitted when the handle is activated and dragging started. |
@end | value |
Emitted when the dragging ended. |
The following CSS variables can be used to customize slider when using default.css
:
--slider-bg: #D1D5DB;
--slider-connect-bg: #10B981;
--slider-connect-bg-disabled: #9CA3AF;
--slider-height: 6px;
--slider-vertical-height: 300px;
--slider-radius: 9999px;
--slider-handle-bg: #fff;
--slider-handle-border: 0;
--slider-handle-width: 16px;
--slider-handle-height: 16px;
--slider-handle-radius: 9999px;
--slider-handle-shadow: 0.5px 0.5px 2px 1px rgba(0,0,0,.32);
--slider-handle-shadow-active: 0.5px 0.5px 2px 1px rgba(0,0,0,.42);
--slider-handle-ring-width: 3px;
--slider-handle-ring-color: #10B98130;
--slider-tooltip-font-size: 0.875rem;
--slider-tooltip-line-height: 1.25rem;
--slider-tooltip-font-weight: 600;
--slider-tooltip-min-width: 20px;
--slider-tooltip-bg: #10B981;
--slider-tooltip-bg-disabled: #9CA3AF;
--slider-tooltip-color: #fff;
--slider-tooltip-radius: 5px;
--slider-tooltip-py: 2px;
--slider-tooltip-px: 6px;
--slider-tooltip-arrow-size: 5px;
--slider-tooltip-distance: 3px;
Override them globally:
:root {
--slider-connect-bg: #3B82F6;
--slider-tooltip-bg: #3B82F6;
--slider-handle-ring-color: #3B82F630;
}
Or on instance level:
<Slider
v-model="value"
class="slider-red"
/>
<Slider
v-model="value"
class="slider-blue"
/>
.slider-red {
--slider-connect-bg: #EF4444;
--slider-tooltip-bg: #EF4444;
--slider-handle-ring-color: #EF444430;
}
.slider-blue {
--slider-connect-bg: #3B82F6;
--slider-tooltip-bg: #3B82F6;
--slider-handle-ring-color: #3B82F630;
}
To use the slider with Tailwind CSS you must add it as a plugin to tailwind.config.js
:
// tailwind.config.js
module.exports = {
// ...
plugins: [
require('@vueform/slider/tailwind'),
]
}
This plugin adds certain utilities and variants which are neccessary for the slider but Tailwind does not provide by default.
After that you need to import themes/tailwind.scss
to you main component:
<template>
<div id="app">
<Slider ... />
</div>
</template>
<script>
// ...
</script>
<style lang="scss">
@import 'path/to/node_modules/@vueform/slider/themes/tailwind.scss'
</style>
Alternatively you can define class names directly by passing them to the Slider
component via classes
property. When using this approach you don't need to import tailwind.scss
. Here's a default styling for Tailwind CSS (the same included in tailwind.scss
):
<Slider v-model="value" :classes="{
target: 'relative box-border select-none touch-none tap-highlight-transparent touch-callout-none disabled:cursor-not-allowed',
focused: 'slider-focused',
tooltipFocus: 'slider-tooltip-focus',
tooltipDrag: 'slider-tooltip-drag',
ltr: 'slider-ltr',
rtl: 'slider-rtl',
horizontal: 'slider-horizontal h-1.5',
vertical: 'slider-vertical w-1.5 h-80',
textDirectionRtl: 'slider-txt-rtl',
textDirectionLtr: 'slider-txt-ltr',
base: 'w-full h-full relative z-1 bg-gray-300 rounded',
connects: 'w-full h-full relative overflow-hidden z-0 rounded',
connect: 'absolute z-1 top-0 right-0 transform-origin-0 transform-style-flat h-full w-full bg-green-500 cursor-pointer tap:duration-300 tap:transition-transform disabled:bg-gray-400 disabled:cursor-not-allowed',
origin: 'slider-origin absolute z-1 top-0 right-0 transform-origin-0 transform-style-flat h-full w-full h:h-0 v:-top-full txt-rtl-h:left-0 txt-rtl-h:right-auto v:w-0 tap:duration-300 tap:transition-transform',
handle: 'absolute rounded-full bg-white border-0 shadow-slider cursor-grab focus:outline-none h:w-4 h:h-4 h:-top-1.5 h:-right-2 txt-rtl-h:-left-2 txt-rtl-h:right-auto v:w-4 v:h-4 v:-top-2 v:-right-1.25 disabled:cursor-not-allowed focus:ring focus:ring-green-500 focus:ring-opacity-30',
handleLower: 'slider-hande-lower',
handleUpper: 'slider-hande-upper',
touchArea: 'h-full w-full',
tooltip: 'absolute block text-sm font-semibold whitespace-nowrap py-1 px-1.5 min-w-5 text-center text-white rounded border border-green-500 bg-green-500 transform h:-translate-x-1/2 h:left-1/2 v:-translate-y-1/2 v:top-1/2 disabled:bg-gray-400 disabled:border-gray-400 merge-h:translate-x-1/2 merge-h:left-auto merge-v:-translate-x-4 merge-v:top-auto tt-focus:hidden tt-focused:block tt-drag:hidden tt-dragging:block',
tooltipTop: 'bottom-6 h:arrow-bottom merge-h:bottom-3.5',
tooltipBottom: 'top-6 h:arrow-top merge-h:top-5',
tooltipLeft: 'right-6 v:arrow-right merge-v:right-1',
tooltipRight: 'left-6 v:arrow-left merge-v:left-7',
tooltipHidden: 'slider-tooltip-hidden',
active: 'slider-active shadow-slider-active cursor-grabbing',
draggable: 'cursor-ew-resize v:cursor-ns-resize',
tap: 'slider-state-tap',
drag: 'slider-state-drag',
}" />
There are certain variants that help detecting different states/config of the slider:
h
- applied when the slider is horizontalv
- applied when the slider is verticalmerge-h
- applied when the slider is horizontal and tooltips are mergedmerge-v
- applied when the slider is horizontal and tooltips are mergeddisabled
- applied when the slider is disabledtxt-rtl-h
- applied when the slider is horizontal and text direction is set tortl
tap
- applied when the slider bar is being taped to jump to certain positiontt-focus
- applied when the slider should only display tooltips on focus (showToolip: 'focus'
) and the slider is not focusedtt-focused
- applied when the slider should only display tooltips on focus and the slider is focusedtt-drag
- applied when the slider should only display tooltips on drag (showToolip: 'drag'
) and the slider is not being draggedtt-dragging
- applied when the slider should only display tooltips on drag and the slider is being dragged
The target
class receives ltr
, rtl
, horizontal
, vertical
, textDirectionRtl
, textDirectionLtr
, focused
, tooltipFocus
, tooltipDrag
, tap
, and drag
classes when the related state is applied.
Certain classes do not define any styles (like .slider-horizontal
, .slider-vertical
) but only required to detect certain states. If you are changing the class list for any class name make sure to always keep the ones that start with slider-
to be able to use the utilities mentioned above (h
, v
, etc).
In case you need to override the same type of utility you might use @neojp/tailwind-important-variant and use eg. bg-green-500!
.
<template>
<Slider
v-model="value"
/>
</template>
<script>
import Slider from '@vueform/slider'
export default {
components: { Slider },
data: () => ({
value: 20
})
}
</script>
<template>
<Slider
v-model="value"
/>
</template>
<script>
import Slider from '@vueform/slider'
export default {
components: { Slider },
data: () => ({
value: [20, 40]
})
}
</script>
<template>
<Slider
v-model="value"
:format="format"
/>
</template>
<script>
import Slider from '@vueform/slider'
export default {
components: { Slider },
data: () => ({
value: 20,
format: function (value) {
return `€${Math.round(value)}`
}
})
}
</script>
<template>
<Slider
v-model="value"
:merge="merge"
:format="format"
/>
</template>
<script>
import Slider from '@vueform/slider'
export default {
components: { Slider },
data: () => ({
value: [20, 30, 40],
merge: 10,
format: {
prefix: '$',
decimals: 2
}
})
}
</script>
<template>
<Slider
v-model="value"
/>
</template>
<script>
import Slider from '@vueform/slider'
export default {
components: { Slider },
data: () => ({
value: 50,
orientation: 'vertical',
direction: 'rtl'
})
}
</script>