Appearance
@vibe-labs/design-vue-sliders
Vue 3 slider component for the Vibe Design System. Single value, range, vertical, marks, tooltips, and multiple thumb shapes — all backed by @vibe-labs/design-components-sliders CSS tokens.
Installation
ts
import { VibeSlider } from "@vibe-labs/design-vue-sliders";Requires the CSS layer from @vibe-labs/design-components-sliders.
Components
VibeSlider
Flexible slider supporting single value, dual-thumb range, vertical orientation, step marks, value tooltips, and multiple thumb shapes.
Usage
vue
<!-- Basic -->
<VibeSlider v-model="volume" :min="0" :max="100" />
<!-- With tooltip on hover -->
<VibeSlider v-model="brightness" tooltip="hover" />
<!-- Always-visible tooltip with formatter -->
<VibeSlider v-model="price" :min="0" :max="1000" :step="10" tooltip="always" :format-value="(v) => `£${v}`" />
<!-- Range (dual-thumb) -->
<VibeSlider v-model="priceRange" :range="true" :min="0" :max="500" :step="5" />
<!-- With marks -->
<VibeSlider v-model="rating" :min="1" :max="5" :step="1" :marks="true" />
<!-- Custom marks with labels -->
<VibeSlider
v-model="temp"
:min="0"
:max="100"
:marks="[
{ value: 0, label: 'Cold' },
{ value: 50, label: 'Warm' },
{ value: 100, label: 'Hot' },
]"
/>
<!-- Sizes -->
<VibeSlider v-model="val" size="sm" />
<VibeSlider v-model="val" size="lg" />
<!-- Thumb shapes -->
<VibeSlider v-model="position" thumb-shape="bar" />
<VibeSlider v-model="position" thumb-shape="pill" />
<!-- Track colors -->
<VibeSlider v-model="health" color="success" />
<VibeSlider v-model="danger" color="danger" />
<!-- Vertical -->
<VibeSlider v-model="level" orientation="vertical" style="height: 200px" />
<!-- Disabled -->
<VibeSlider v-model="locked" :disabled="true" />
<!-- Decimal step -->
<VibeSlider v-model="opacity" :min="0" :max="1" :step="0.01" :format-value="(v) => `${Math.round(v * 100)}%`" />Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | number | [number, number] | — | Value (number for single, tuple for range) |
min | number | 0 | Minimum value |
max | number | 100 | Maximum value |
step | number | 1 | Step increment |
range | boolean | false | Enable dual-thumb range mode |
size | SliderSize | "md" | sm · md · lg |
orientation | SliderOrientation | "horizontal" | horizontal · vertical |
thumbShape | SliderThumbShape | "circle" | circle · bar · pill · none |
color | SliderTrackColor | "accent" | accent · success · warning · danger |
tooltip | SliderTooltipMode | "none" | none · hover · always |
marks | boolean | number[] | SliderMark[] | — | Show marks (true = auto from step, capped at 50) |
formatValue | (value: number) => string | String | Format value for tooltip and aria-valuetext |
disabled | boolean | false | Disabled state |
ariaLabel | string | — | Accessible label for single / first thumb |
ariaLabelEnd | string | — | Accessible label for second thumb (range) |
id | string | auto | HTML id |
name | string | — | Form name (range adds -end suffix for second input) |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue | number | [number, number] | Value changed |
dragStart | SliderDragEvent | Thumb drag started |
dragEnd | SliderDragEvent | Thumb drag finished |
Exposed Methods
| Method | Description |
|---|---|
focus() | Focus the first (or only) thumb |
blur() | Blur the active thumb |
value | Computed current value (reactive) |
Keyboard
| Key | Action |
|---|---|
| ArrowRight / ArrowUp | Increase by step |
| ArrowLeft / ArrowDown | Decrease by step |
| PageUp | Increase by 10× step or 10% of range |
| PageDown | Decrease by 10× step or 10% of range |
| Home | Jump to minimum |
| End | Jump to maximum |
Accessibility
- Each thumb has
role="slider"with full ARIA attributes aria-valuemin,aria-valuemax,aria-valuenow,aria-valuetextaria-orientationfor vertical mode- Hidden
<input type="range">elements for form submission - Range mode constrains
aria-valuemin/aria-valuemaxper thumb to prevent overlap - Focus ring via
:focus-visibleon thumb elements
Composables
useSliderDrag(options)
Core composable for pointer, touch, and keyboard interaction. Handles step snapping, range thumb clamping, floating-point precision, and vertical orientation.
ts
import { useSliderDrag } from "@vibe-labs/design-vue-sliders";
const { isDragging, activeThumb, thumbPercents, onThumbDown, onTrackDown, onKeyDown, valueToPercent, percentToValue } = useSliderDrag({
trackEl,
min: toRef(props, "min"),
max: toRef(props, "max"),
step: toRef(props, "step"),
orientation: toRef(props, "orientation"),
disabled: toRef(props, "disabled"),
values: internalValues,
range: toRef(props, "range"),
onUpdate: (index, value) => {
/* emit */
},
});Key features:
- Pointer capture — reliable drag even outside the slider bounds
- Click-to-jump — clicking the track moves the nearest thumb
- Range clamping — thumbs can't cross each other
- Step snapping — values always land on valid steps
- Float precision — no
0.1 + 0.2 = 0.300000004artifacts
Types
ts
interface SliderMark {
value: number;
label?: string;
}
type SliderMarkProp = boolean | number[] | SliderMark[];
type SliderFormatFn = (value: number) => string;
interface SliderDragEvent {
thumb: 0 | 1;
value: number;
}Dependencies
| Package | Purpose |
|---|---|
@vibe-labs/design-components-sliders | CSS tokens + generated styles |
Build
bash
npm run buildBuilt with Vite + vite-plugin-dts. Outputs ES module with TypeScript declarations.