Skip to content

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 value
  • max (number): Maximum value
  • step (number): Step increment
  • marks (object): Mark points
  • range (boolean): Enable range selection
  • disabled (boolean): Disable slider
  • tooltip (boolean): Show value tooltip
  • vertical (boolean): Vertical orientation
  • reverse (boolean): Reverse direction
  • size (string): Component size
  • color (string): Track color
  • tooltipPlacement (string): Tooltip position

Events

  • update:modelValue: Value updated
  • change: Value changed
  • dragstart: Drag started
  • dragend: Drag ended
  • focus: Slider focused
  • blur: Slider blurred

Slots

  • mark: Custom mark content
  • tooltip: Custom tooltip content
  • thumb: Custom thumb content
  • track: Custom track content

Usage Examples

  1. Basic Slider:
<template>
<UISlider
v-model="volume"
:min="0"
:max="100"
:step="1"
/>
</template>
<script setup>
const volume = ref(50)
</script>
  1. 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>
  1. 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

  1. User Experience:

    • Clear value display
    • Smooth interactions
    • Appropriate step size
    • Visual feedback
  2. Accessibility:

    • Keyboard support
    • ARIA labels
    • Focus states
    • Screen reader support
  3. Visual Design:

    • Clear track
    • Visible thumb
    • Readable marks
    • Consistent styling
  4. Responsiveness:

    • Touch support
    • Mobile friendly
    • Adaptive sizing
    • Clear interaction areas

Common Use Cases

  1. 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>
  1. 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>
  1. 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 = 0
const maxPrice = 1000
const 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>