Corner Radius Slider
An Apple-style slider component for Vue with tick marks, a minimal thumb, and smooth pointer tracking. Perfect for design tools, settings panels, or any UI that needs a polished numeric input.
sliderappleiosvuenuxttailwindinputdesign-tool
Preview
Corner Radius23
Code
Corner Radius Slider.vue
<template> <div class="w-full"> <span class="block text-[13px] font-medium text-[#86868b] tracking-wide uppercase mb-2.5 pl-1.5"> {{ label }} </span>
<div class="bg-white/80 backdrop-blur-2xl backdrop-saturate-[1.6] rounded-2xl p-1 flex items-center gap-4 shadow-[0_0_0_0.5px_rgba(0,0,0,0.06),0_2px_8px_rgba(0,0,0,0.04),0_8px_24px_rgba(0,0,0,0.06)] select-none"> <div ref="trackRef" class="flex-1 h-12.25 flex items-center relative cursor-ew-resize touch-none rounded-[18px]" @pointerdown="onPointerDown" @pointermove="onPointerMove" @pointerup="onPointerUp" @pointercancel="onPointerUp" > <!-- Ticks --> <div class="absolute left-3 right-3 flex items-center justify-between z-0"> <div v-for="(_, i) in tickCount" :key="i" class="w-[1.5px] rounded-sm transition-colors duration-150" :class="[ i % 5 === 0 ? 'h-4' : 'h-2.5', (i / (tickCount - 1)) * 100 <= percentage ? 'bg-black/25' : 'bg-black/10', ]" /> </div>
<!-- Thumb --> <div class="bg-[#f2f2f2] rounded-lg h-full flex justify-end items-center relative z-10" :style="{ width: percentage + '%', minWidth: '24px' }" > <div class="mr-2 shrink-0 w-1 h-5.5 rounded-[2.5px] shadow-[0_0.5px_2px_rgba(0,0,0,0.12)] transition-colors duration-200" :class="isDragging ? 'bg-black/50' : 'bg-[rgba(117,117,117,0.8)]'" /> </div> </div>
<span class="text-base font-medium tabular-nums text-[#1d1d1f] min-w-8.5 text-right -tracking-[0.5px] shrink-0 mr-2"> {{ modelValue }} </span> </div> </div></template>
<script setup lang="ts">import { ref, computed } from 'vue'
const props = withDefaults(defineProps<{ modelValue?: number min?: number max?: number tickCount?: number label?: string}>(), { modelValue: 23, min: 0, max: 50, tickCount: 11, label: 'Corner Radius',})
const emit = defineEmits<{ 'update:modelValue': [value: number]}>()
const trackRef = ref<HTMLElement | null>(null)const isDragging = ref(false)
const percentage = computed( () => ((props.modelValue - props.min) / (props.max - props.min)) * 100)
function updateValue(clientX: number) { const track = trackRef.value if (!track) return const rect = track.getBoundingClientRect() const pad = 12 const ratio = Math.max(0, Math.min(1, (clientX - rect.left - pad) / (rect.width - pad * 2))) emit('update:modelValue', Math.round(ratio * (props.max - props.min) + props.min))}
function onPointerDown(e: PointerEvent) { isDragging.value = true updateValue(e.clientX) ;(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId)}
function onPointerMove(e: PointerEvent) { if (!isDragging.value) return updateValue(e.clientX)}
function onPointerUp() { isDragging.value = false}</script>
Stop recreating designs you've already seen
Join now and get 30% off your first year as an early supporter.
One email on launch day. That's it.