Components
Checkbox
shadcn's Checkbox where checking drops goo into the box. It splats, splashes, and sucks back up when you uncheck.
Customize
GoopCheckbox wraps reka-ui's CheckboxRoot and CheckboxIndicator, the same primitive as shadcn-vue's Checkbox, with the same API and classes. v-model (including 'indeterminate'), disabled, name, required, value, asChild, keyboard handling, and role="checkbox" all come from reka-ui. The goo is a layer inside the box.
Installation
Install @goopui/nuxt or @goopui/vue as shown on the Button page. The Nuxt module auto-imports GoopCheckbox. It uses the same shadcn tokens as the plain Checkbox (--primary, --primary-foreground, --input, --ring).
Usage
<script setup lang="ts">
// Nuxt auto-imports this. In plain Vue, import it:
import { GoopCheckbox } from '@goopui/vue'
const terms = ref(false)
</script>
<template>
<label class="flex items-center gap-2 text-sm">
<GoopCheckbox v-model="terms" />
Accept terms and conditions
</label>
</template>
What it does
- Checking. A drop falls into the box from above, stretched along its fall. On impact the fill swells out of it and splats flat against the floor, then wobbles. A few droplets splash out sideways. The check mark appears once the splat has mostly settled.
- Unchecking. The fill sucks up into a drop above the box on a neck. The neck snaps, and the drop swells and pops into specks.
- Indeterminate. A goo bar stretches across the middle and wobbles. From checked, the fill drains into it.
The check mark is the same unfiltered icon as shadcn's, so it stays sharp. It is only held back until the goo lands.
Indeterminate
v-model takes true, false, or 'indeterminate', as in reka-ui:
<script setup lang="ts">
import type { CheckboxState } from '@goopui/core'
const all = ref<CheckboxState>('indeterminate')
</script>
<template>
<GoopCheckbox v-model="all" />
</template>
Effects and presets
Every effect is a prop. false turns it off, true uses the preset's strength, and a number scales it (0 is off). fill is on or off only.
<GoopCheckbox :splat="false" />
<GoopCheckbox :droplets="false" />
<GoopCheckbox preset="wild" />
<GoopCheckbox :speed="0.5" />
Disabled and goo off
<GoopCheckbox disabled />
<GoopCheckbox disabled default-value />
<GoopCheckbox :goo="false" />
Colors
The fill and droplets use the --goop-checkbox-fill variable, which defaults to var(--primary), the color shadcn fills a checked box with. Override it on the element or an ancestor:
<GoopCheckbox class="[--goop-checkbox-fill:var(--color-emerald-500)] data-checked:border-emerald-500" />
Props
GoopCheckbox keeps the shadcn-vue Checkbox API and adds the goo props.
| Prop | Type | Default | Notes |
|---|---|---|---|
modelValue | boolean | 'indeterminate' | The controlled state (v-model). | |
defaultValue | boolean | 'indeterminate' | false | The initial state when uncontrolled. |
disabled | boolean | false | |
id, name, value, required | Passed to reka-ui. name and value make it submit with a form. | ||
asChild, as | The element to render, via reka-ui. | ||
class | string | array | object | Merged onto the box. | |
goo | boolean | true | Master switch. false renders a plain shadcn Checkbox. |
fill | boolean | number | true | The check fills the box with goo instead of a flat colour. |
splat | boolean | number | true | The goo splats into the box on check and wobbles to rest. |
droplets | boolean | number | true | A few droplets fly off on impact and fall back. |
speed | number | 1 | Speed multiplier. |
preset | 'subtle' | 'playful' | 'wild' | app config, then playful | The feel. |
renderer | 'svg' | 'canvas' | 'svg' | How the goo is drawn. |
The default slot replaces the check mark. It receives reka-ui's slot props. GoopCheckbox also exposes handle (the live checkbox handle, null before mount or with goo off) and el (the box).
Before it mounts, during SSR, and with :goo="false", it is a plain shadcn Checkbox, so first paint and hydration match.
Accessibility
It's a real reka-ui checkbox: role="checkbox", aria-checked (mixed when indeterminate), focus ring, Space to toggle. The goo layer is aria-hidden and can't be clicked.
Reduced motion keeps the goo shape and turns off the simulation: the box fills, or shows its bar, straight away, with no drop, splat, droplets, or suck-up. See Accessibility & reduced motion.