Vueform is a comprehensive form builder for Vue.js that makes form development a breeze. It standardizes and handles the entire form building process, including:
- a complete theming and templating system with Tailwind support (similar to @vueform libraries)
- 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
- dynamic form rendering with JSON support
- translating form content and global i18n support.
Vueform pre-release is open for registration for the first 100 developers with special discounts.
Learn more: 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>