Components
Sheet New · experimental
shadcn's Sheet with goo. The panel blooms out of its screen edge, wobbles, and splashes.
Customize
GoopSheet wraps the same reka-ui Dialog primitive as shadcn-vue's Sheet, with the same API. Focus trapping, scroll locking, and dismissal work the same. Swap the imports and you're done.
Installation
Nuxt
pnpm add @goopui/nuxt
export default defineNuxtConfig({
modules: ['@goopui/nuxt'],
})
The module auto-imports every GoopSheet* part, adds goop.css, and points Tailwind at the component classes. It needs Tailwind CSS v4 and the shadcn tokens (--background, --foreground, --ring).
Vue
pnpm add @goopui/vue
@import "tailwindcss";
@import "@goopui/vue/goop.css";
Usage
<script setup lang="ts">
// Nuxt auto-imports these. In plain Vue, import them:
import {
GoopButton,
GoopSheet,
GoopSheetClose,
GoopSheetContent,
GoopSheetDescription,
GoopSheetFooter,
GoopSheetHeader,
GoopSheetTitle,
GoopSheetTrigger,
} from '@goopui/vue'
</script>
<template>
<GoopSheet>
<GoopSheetTrigger as-child>
<GoopButton variant="outline">Open sheet</GoopButton>
</GoopSheetTrigger>
<GoopSheetContent>
<GoopSheetHeader>
<GoopSheetTitle>Edit profile</GoopSheetTitle>
<GoopSheetDescription>Make changes to your profile here.</GoopSheetDescription>
</GoopSheetHeader>
<GoopSheetFooter>
<GoopSheetClose as-child>
<GoopButton>Save changes</GoopButton>
</GoopSheetClose>
</GoopSheetFooter>
</GoopSheetContent>
</GoopSheet>
</template>
The parts are GoopSheet, GoopSheetTrigger, GoopSheetContent, GoopSheetHeader, GoopSheetFooter, GoopSheetTitle, GoopSheetDescription, and GoopSheetClose. All the goo lives on GoopSheetContent, which also renders the overlay and the close button.
Behavior
- Open. A blob appears at the middle of the sheet's screen edge and spreads in lobes until it fills the sheet. It overshoots the inner edge and wobbles to rest (
wobble,openSlosh). - Splash. Globs, drops, and specks fling off the inner edge and the sides, fall, and fade. None are thrown off-screen (
openDrips). Then nothing moves. - Close. The goo pulls in, wobbles, and shrinks back into the edge (
closeSlosh). The overlay fades out over the same time. - Content stays sharp. Only the sheet's background, border, and shadow are goo. They're drawn on an
aria-hiddensurface behind your content, so text and inputs are never filtered. - Canvas by default. A sheet is a big surface, so it draws with the canvas renderer unless a prop or the app config says otherwise.
Sides
side picks the edge, like shadcn. The bloom always starts from the middle of that edge:
<GoopSheetContent side="top">...</GoopSheetContent>
<GoopSheetContent side="left">...</GoopSheetContent>
Splash knobs
The bloom and its splash take the same knobs as Dialog. bloomStart="merge" starts from a few drops that fuse instead of one. The four numeric props only matter while openDrips is on:
openDripAmount(0 to 3): how many drops.openDripSize(0.3 to 2.5): how big.openDripFling(0 to 3): how far they fly.openDripVariety(0 to 1): the mix of big globs and specks. 0 makes them all alike.
sloshVariety (0 to 1) sets how differently each side bulges. 0 is an even, centred bulge.
<GoopSheetContent bloom-start="merge" :open-drip-amount="2" :open-drip-size="1.6" :open-drip-fling="2">
...
</GoopSheetContent>
<GoopSheetContent :open-drips="false">...</GoopSheetContent>
openSlosh, openDrips, and closeSlosh take true, false, or a strength from 0 to 2.
Plain shadcn
:goo="false" renders exactly shadcn's SheetContent, with its own slide in and out:
<GoopSheetContent :goo="false">...</GoopSheetContent>
Driving it from code
GoopSheetContent exposes its engine handle as handle (null before it mounts, or when goo is off). The panel only exists while open.
Props
The root, trigger, close, header, footer, title, and description take shadcn-vue's props. GoopSheetContent takes reka-ui's DialogContent props, class, and these:
| Prop | Type | Default | Notes |
|---|---|---|---|
side | 'top' | 'right' | 'bottom' | 'left' | 'right' | The screen edge the sheet comes in from. The goo blooms from the middle of it. |
showCloseButton | boolean | true | Show the X close button in the top-right corner, like shadcn. |
goo | boolean | true | Master switch. false renders a plain shadcn SheetContent that slides in and out. |
bloomStart | 'single' | 'merge' | 'single' | How the bloom starts: one droplet swells at the edge, or a few drops fuse. |
wobble | boolean | true | The open overshoot past the inner edge and its jelly settle. |
fade | boolean | true | The content fades in once the goo has mostly spread, and out first on close. |
openSlosh | boolean | number | true | On open, the edges bulge past rest, rebound, and wobble. A number from 0 to 2 sets the strength. |
openDrips | boolean | number | true | On open, the big splash: globs, drops, and specks fling off the inner edge and sides, fall, and fade. None go off-screen. A number from 0 to 2 sets the strength. |
openDripAmount | number | 1 | Splash drop count, 0 to 3. |
openDripSize | number | 1 | Splash drop size, 0.3 to 2.5. |
openDripFling | number | 1 | How far the drops are flung before they fall, 0 to 3. |
openDripVariety | number | 0.7 | Mix of big globs and specks, and how uneven the spray is, 0 to 1. 0 makes every drop alike. |
sloshVariety | number | 1 | How differently each side bulges on open and close (off-centre, one or two lumps, staggered), 0 to 1. 0 is an even, centred bulge. |
closeSlosh | boolean | number | true | On close, the goo pulls in and wobbles before it shrinks back into the edge. A number from 0 to 2 sets the strength. |
speed | number | 1 | Animation speed multiplier. |
preset | 'subtle' | 'playful' | 'wild' | app config, then playful | The overall feel. |
renderer | 'svg' | 'canvas' | app config, then 'canvas' | How the goo is drawn. A sheet is a big surface, so it uses canvas unless you or the app config say otherwise. |
Accessibility
Focus trapping, scroll locking, Escape and outside-click dismissal, and ARIA attributes come from reka-ui. The goo surface is aria-hidden and can't be clicked, and your content is never filtered. Under reduced motion the sheet opens and closes plainly: it keeps its goo color, but the bloom, slosh, splash, and wobble are all turned off. See Accessibility & reduced motion.