Components
Progress
shadcn's Progress that fills like liquid. The front bulges when the value changes, and a drip falls now and then.
Customize
Installation
Nuxt
pnpm add @goopui/nuxt
export default defineNuxtConfig({
modules: ['@goopui/nuxt'],
})
The module auto-imports GoopProgress and adds goop.css. See Installation for the module options.
Vue
pnpm add @goopui/vue
@import "tailwindcss";
@import "@goopui/vue/goop.css";
Usage
GoopProgress wraps the same reka-ui Progress as shadcn-vue's Progress. The API is the same: v-model is a number from 0 to max (default 100), and reka-ui keeps role="progressbar" and the ARIA values.
<script setup lang="ts">
// Nuxt auto-imports this. In plain Vue, import it:
import { GoopProgress } from '@goopui/vue'
const progress = ref(35)
</script>
<template>
<GoopProgress v-model="progress" />
</template>
Behavior
- Front. The leading edge is a rounded blob that chases the value on a soft spring and stretches with its speed. It bulges and wobbles each time the value changes (
wobble). - Slosh. The top surface of the fill carries a slow wave. It piles up toward the front when the fill speeds up and sloshes back when it stops (
slosh). - Drips. Now and then a drop swells on the underside of the front, necks off, and falls (
drips). At most three at once. The bar is a thin strip, so the drops are drawn in the goo layer around it and never change layout. - Layout never changes. The goo is drawn in one
aria-hiddenlayer on the root. The real indicator stays in place and goes see-through.
Auto-updating
The fill follows whatever value you give it, so bursty updates look best. This one fills in uneven bursts, holds at 100, and starts over:
<GoopProgress :model-value="progress" />
Taller bars
The goo follows the root's box, so a taller bar has more room for the front and the drips. Set the height with class:
<GoopProgress :model-value="65" class="h-3" />
Indeterminate
Pass null when you don't know the value. A goo slug runs along the bar with the same surge as GoopSpinner, stretching when it's fast, and it drips too.
<GoopProgress :model-value="null" />
<GoopProgress :model-value="null" class="h-3" />
Color
The goo is painted in --primary. To change it, set --goop-progress-color on the bar or any ancestor:
<GoopProgress :model-value="60" class="[--goop-progress-color:var(--destructive)]" />
The track keeps shadcn's bg-muted. Style it with class as you would in shadcn. Use :goo="false" to render a plain shadcn Progress.
Props
GoopProgress keeps the shadcn-vue Progress API and adds the goo props.
| Prop | Type | Default | Notes |
|---|---|---|---|
modelValue | number | null | 0 | The value (v-model). null is indeterminate. |
max | number | 100 | The value that means full. |
getValueLabel, getValueText | (value, max) => string | Passed to reka-ui, for the ARIA value text. | |
as, asChild | Render a different element. | ||
class | string | array | object | Merged onto the root, like shadcn. | |
goo | boolean | true | Master switch. false renders a plain shadcn Progress. |
slosh | boolean | number | true | The top surface waves, piles up toward the front, and sloshes back. |
drips | boolean | number | true | Drops form on the front's underside now and then and fall. |
wobble | boolean | number | true | The front bulges and wobbles when the value changes. |
seed | number | 0 | Varies drip timing and sizes, so two bars don't drip in step. |
speed | number | 1 | Animation 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.
GoopProgress also exposes handle (the core handle, null before mount or with goo off) and el.
Accessibility
It's a real reka-ui progress bar: role="progressbar" with aria-valuenow, aria-valuemin, and aria-valuemax, and no value attributes when indeterminate. Pass aria-label (it lands on the root) so the bar has a name. The goo layer is aria-hidden. Under reduced motion the goo keeps its shape and the effects turn off: the front moves straight to the value, there's no slosh, wobble, or drips, and the indeterminate slug sits still in the middle of the bar. See Accessibility & reduced motion.