Sheet

Components

Sheet New · experimental

shadcn's Sheet with goo. The panel blooms out of its screen edge, wobbles, and splashes.

Open it, then close it. The goo pools at the edge and spreads to fill the sheet.

Customize

Side
Preset
Speed 1.00×
Open slosh 1.00×
Open drips 1.00×
Close slosh 1.00×
Bloom start

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
nuxt.config.ts
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
main.css
@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-hidden surface 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:

GoopSheetContent props
PropTypeDefaultNotes
side'top' | 'right' | 'bottom' | 'left''right'The screen edge the sheet comes in from. The goo blooms from the middle of it.
showCloseButtonbooleantrueShow the X close button in the top-right corner, like shadcn.
goobooleantrueMaster 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.
wobblebooleantrueThe open overshoot past the inner edge and its jelly settle.
fadebooleantrueThe content fades in once the goo has mostly spread, and out first on close.
openSloshboolean | numbertrueOn open, the edges bulge past rest, rebound, and wobble. A number from 0 to 2 sets the strength.
openDripsboolean | numbertrueOn 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.
openDripAmountnumber1Splash drop count, 0 to 3.
openDripSizenumber1Splash drop size, 0.3 to 2.5.
openDripFlingnumber1How far the drops are flung before they fall, 0 to 3.
openDripVarietynumber0.7Mix of big globs and specks, and how uneven the spray is, 0 to 1. 0 makes every drop alike.
sloshVarietynumber1How differently each side bulges on open and close (off-centre, one or two lumps, staggered), 0 to 1. 0 is an even, centred bulge.
closeSloshboolean | numbertrueOn close, the goo pulls in and wobbles before it shrinks back into the edge. A number from 0 to 2 sets the strength.
speednumber1Animation speed multiplier.
preset'subtle' | 'playful' | 'wild'app config, then playfulThe 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.