Slider

Components

Slider

shadcn's Slider with a liquid fill and a jelly thumb. Drag fast, then stop, and watch it settle.

50
Drag fast and let go. Click the track to jump.

Customize

Preset
Colour
Speed 1.00×

Installation

Nuxt

pnpm add @goopui/nuxt
nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@goopui/nuxt'],
})

The module auto-imports GoopSlider and adds goop.css. See Installation for the module options.

Vue

pnpm add @goopui/vue
main.css
@import "tailwindcss";
@import "@goopui/vue/goop.css";

Usage

GoopSlider wraps the same reka-ui Slider as shadcn-vue's Slider. The API is the same: v-model is an array with one number per thumb, and min, max, step, orientation, dir, inverted, disabled, name, and minStepsBetweenThumbs pass through to reka-ui.

<script setup lang="ts">
// Nuxt auto-imports this. In plain Vue, import it:
import { GoopSlider } from '@goopui/vue'

const volume = ref([50])
</script>

<template>
  <GoopSlider v-model="volume" :max="100" :step="1" />
</template>

It emits update:modelValue while you drag, and valueCommit when you let go.

Behavior

  • Jelly. The thumb follows your pointer on a spring. It lags, overshoots, and wobbles to rest (jelly).
  • Slosh. The surface of the fill piles up toward the front when you move fast, then sloshes back and waves (slosh).
  • Stretch. The thumb stretches along the track with speed (stretch).
  • Splat. Click the track and the thumb jumps there, landing with a small splat (splat).
  • Layout never changes. The goo is drawn in one aria-hidden layer on the slider root. The real range and thumbs stay in place and go see-through, so reka-ui keeps drag, keyboard, focus, and ARIA exactly as they were.
  • The thumb keeps its hover and focus ring.

Range

Pass two numbers for a range slider. The liquid fills between the thumbs:

25 to 75
<GoopSlider v-model="range" :max="100" :step="1" />
const range = ref([25, 75])

Vertical

<div class="h-44">
  <GoopSlider v-model="level" orientation="vertical" :max="100" />
</div>

Steps

With step, every move is a small jump. The thumb still lags and settles.

30
<GoopSlider v-model="quality" :max="100" :step="10" />

Effects and presets

Each effect is a prop. false turns it off, true uses the preset's strength, and a number from 0 to 2 scales it. preset picks subtle, playful (default), or wild for the whole slider. The first slider below has no jelly or stretch, then come wild and subtle:

<GoopSlider :default-value="[40]" :jelly="false" :stretch="false" />
<GoopSlider :default-value="[60]" preset="wild" />
<GoopSlider :default-value="[60]" preset="subtle" />

Disabled

A disabled slider ignores the pointer and goes to half opacity, like shadcn's.

<GoopSlider :default-value="[40]" disabled />

Use :goo="false" to render a plain shadcn Slider.

Color

The goo is painted in --primary. To change it, set --goop-slider-color on the slider or any ancestor:

<GoopSlider :default-value="[50]" class="[--goop-slider-color:var(--destructive)]" />

The track keeps shadcn's bg-muted. Style it with class as you would in shadcn.

Driving it from code

GoopSlider exposes the core handle and its root element. handle.measure() re-measures the thumbs after you change the layout by hand. handle is null before mount and when goo is off.

<script setup lang="ts">
const slider = useTemplateRef('slider')
</script>

<template>
  <GoopSlider ref="slider" :default-value="[50]" />
  <button @click="slider?.handle?.measure()">Re-measure</button>
</template>

Props

GoopSlider keeps the shadcn-vue Slider API and adds the goo props.

GoopSlider props
PropTypeDefaultNotes
modelValuenumber[]One number per thumb (v-model).
defaultValuenumber[]The initial value when uncontrolled.
min, max, stepnumber0, 100, 1Same as reka-ui.
orientation'horizontal' | 'vertical''horizontal'The goo follows it.
dir'ltr' | 'rtl'Reading direction.
invertedbooleanfalseFill from the other end.
minStepsBetweenThumbsnumberFor range sliders.
thumbAlignment'contain' | 'overflow'Passed to reka-ui.
disabled, name, requiredSame as reka-ui.
as, asChildRender a different element.
classstring | array | objectMerged onto the root, like shadcn.
goobooleantrueMaster switch. false renders a plain shadcn Slider.
jellyboolean | numbertrueThe thumb lags on a spring, overshoots, and wobbles to rest.
sloshboolean | numbertrueThe fill's surface piles up, sloshes back, and waves.
stretchboolean | numbertrueThe thumb stretches along the slider with speed.
splatboolean | numbertrueA jumping thumb lands with a small splat.
speednumber1Animation speed multiplier.
preset'subtle' | 'playful' | 'wild''playful'The feel. Falls back to the app config, then --goop-preset.
renderer'svg' | 'canvas''svg'How the goo is drawn.

Effect props take true, false, or a number from 0 to 2. Props win over the app-wide config (GoopPlugin or the module options), which wins over the preset.

Accessibility

It's a real reka-ui slider: each thumb has role="slider" and the ARIA values, and arrow keys, Home, End, and Page Up/Down work as in shadcn. The goo layer is aria-hidden and can't be clicked. An aria-label you pass lands on the slider root, as in shadcn. Under reduced motion the goo keeps its shape and the effects turn off: no jelly, slosh, stretch, or splat. The thumb just follows the value. See Accessibility & reduced motion.