UISlider
UISlider
A versatile slider component that allows users to select single or range values with support for steps, marks, tooltips, and custom styling.
<template> <UISlider v-model="value" :min="0" :max="100" :step="1" :marks="marks" :tooltip="true" class="w-full max-w-md" @change="handleChange" /></template>
<script setup lang="ts">const value = ref(50)
const marks = { 0: '0%', 25: '25%', 50: '50%', 75: '75%', 100: '100%'}
const handleChange = (newValue: number) => { console.log('Value changed:', newValue)}</script>Props
modelValue(number | [number, number]): Current value(s)min(number): Minimum valuemax(number): Maximum valuestep(number): Step incrementmarks(object): Mark pointsrange(boolean): Enable range selectiondisabled(boolean): Disable slidertooltip(boolean): Show value tooltipvertical(boolean): Vertical orientationreverse(boolean): Reverse directionsize(string): Component sizecolor(string): Track colortooltipPlacement(string): Tooltip position
Events
update:modelValue: Value updatedchange: Value changeddragstart: Drag starteddragend: Drag endedfocus: Slider focusedblur: Slider blurred
Slots
mark: Custom mark contenttooltip: Custom tooltip contentthumb: Custom thumb contenttrack: Custom track content
Usage Examples
- Basic Slider:
<template> <UISlider v-model="volume" :min="0" :max="100" :step="1" /></template>
<script setup>const volume = ref(50)</script>- Range Slider with Custom Marks:
<template> <div class="space-y-6"> <UISlider v-model="priceRange" :min="0" :max="1000" :step="50" :marks="priceMarks" :range="true" class="mb-4" > <template #mark="{ value }"> <span class="text-sm"> ${{ value }} </span> </template>
<template #tooltip="{ value }"> <div class="px-2 py-1 bg-gray-900 text-white rounded text-sm"> ${{ value }} </div> </template> </UISlider>
<div class="flex justify-between text-sm text-gray-600"> <span>Min: ${{ priceRange[0] }}</span> <span>Max: ${{ priceRange[1] }}</span> </div> </div></template>
<script setup>const priceRange = ref([200, 800])
const priceMarks = { 0: '$0', 250: '$250', 500: '$500', 750: '$750', 1000: '$1000'}</script>- Custom Styled Slider:
<template> <UISlider v-model="progress" :min="0" :max="100" :step="1" class="custom-slider" > <template #track="{ percent }"> <div class="h-2 rounded-full bg-gray-200"> <div class="h-full rounded-full bg-gradient-to-r from-blue-500 to-purple-500" :style="{ width: `${percent}%` }" /> </div> </template>
<template #thumb> <div class="w-6 h-6 rounded-full bg-white shadow-lg border-2 border-purple-500 transform -translate-x-1/2 -translate-y-1/2" /> </template> </UISlider></template>
<script setup>const progress = ref(60)</script>
<style>.custom-slider { @apply relative py-4;}
.custom-slider:hover .thumb { @apply scale-110;}</style>Best Practices
-
User Experience:
- Clear value display
- Smooth interactions
- Appropriate step size
- Visual feedback
-
Accessibility:
- Keyboard support
- ARIA labels
- Focus states
- Screen reader support
-
Visual Design:
- Clear track
- Visible thumb
- Readable marks
- Consistent styling
-
Responsiveness:
- Touch support
- Mobile friendly
- Adaptive sizing
- Clear interaction areas
Common Use Cases
- Volume Control:
<template> <div class="flex items-center space-x-4"> <VolumeIcon :class="[ 'w-5 h-5', volume === 0 ? 'text-gray-400' : 'text-primary-600' ]" />
<UISlider v-model="volume" :min="0" :max="100" :step="1" class="w-32" />
<span class="text-sm tabular-nums"> {{ volume }}% </span> </div></template>- Image Editor:
<template> <div class="space-y-4"> <div class="aspect-video bg-gray-100 rounded-lg overflow-hidden" :style="imageStyles" > <img :src="imageUrl" class="w-full h-full object-cover" /> </div>
<div class="grid grid-cols-2 gap-4"> <div class="space-y-2"> <label class="text-sm font-medium"> Brightness </label> <UISlider v-model="filters.brightness" :min="0" :max="200" :step="1" @change="updateFilters" /> </div>
<div class="space-y-2"> <label class="text-sm font-medium"> Contrast </label> <UISlider v-model="filters.contrast" :min="0" :max="200" :step="1" @change="updateFilters" /> </div>
<div class="space-y-2"> <label class="text-sm font-medium"> Saturation </label> <UISlider v-model="filters.saturation" :min="0" :max="200" :step="1" @change="updateFilters" /> </div> </div> </div></template>
<script setup>const filters = reactive({ brightness: 100, contrast: 100, saturation: 100})
const imageStyles = computed(() => ({ filter: `brightness(${filters.brightness}%) contrast(${filters.contrast}%) saturate(${filters.saturation}%)`}))</script>- Price Range Filter:
<template> <div class="filter-section"> <h3 class="text-lg font-medium mb-4"> Price Range </h3>
<UISlider v-model="priceFilter" :min="minPrice" :max="maxPrice" :step="10" :range="true" class="mb-4" > <template #tooltip="{ value }"> <div class="px-2 py-1 bg-gray-900 text-white rounded"> {{ formatCurrency(value) }} </div> </template> </UISlider>
<div class="flex items-center space-x-4"> <UIInput v-model.number="priceFilter[0]" type="number" :min="minPrice" :max="priceFilter[1]" class="w-24" />
<span class="text-gray-500">to</span>
<UIInput v-model.number="priceFilter[1]" type="number" :min="priceFilter[0]" :max="maxPrice" class="w-24" /> </div>
<div class="mt-4"> <UIButton size="sm" @click="applyPriceFilter" > Apply Filter </UIButton> </div> </div></template>
<script setup>const minPrice = 0const maxPrice = 1000const priceFilter = ref([minPrice, maxPrice])
const formatCurrency = (value: number) => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(value)
const applyPriceFilter = () => { // Apply price filter logic}</script>