Getting Started
Introduction
goopUI is the shadcn catalog made gooey. Same components, same API, built on reka-ui, with a small physics engine that makes them swell, squish, and drip.
goopUI copies shadcn's components one by one. Each one wraps the same reka-ui primitive that shadcn-vue uses and keeps the same API: cva variants, class passthrough, and asChild. The difference is a layer of goo behind it. Hover a button and drips swell off its bottom edge, neck, and fall. Press it and it squishes, then springs back.
How it works
Every component has two layers:
- Your content. The real button, label, and icon. Nothing filters it, so text stays crisp and accessible.
- The goo layer. An
aria-hiddenelement under the content withpointer-events: none, holding the body shape and drip circles. An SVG goo filter (blur, then a sharp alpha threshold) melts the circles into one liquid shape.
The goo layer is padded outside the element, so drips can hang and fall without changing your layout. Its color is the variant's background token (--primary, --destructive, and so on).
It also reacts to how you move: fast entries splash goo out the far side, clicks send a shockwave, and the goo carries your pointer's momentum. An optional oil finish adds an iridescent sheen.
Drips run on a small spring and gravity integrator. Every instance on the page shares one requestAnimationFrame loop, and that loop stops when nothing is moving. It draws with an SVG filter by default (only transform and opacity change per frame) or with a shared WebGL canvas.
Packages
| Package | What it is | Status |
|---|---|---|
@goopui/core | The engine. Plain TypeScript and DOM, with no framework and no dependencies. SSR-safe. | Alpha |
@goopui/vue | Vue components (SFCs) on top of core and reka-ui. Works in plain Vue/Vite. | Alpha |
@goopui/nuxt | Nuxt module that auto-imports the Vue components and injects goop.css. | Alpha |
@goopui/react | React components | Later |
@goopui/svelte | Svelte components | Later |
Components
Each component keeps the shadcn-vue API and adds goo props. Every effect can be switched off on its own, and :goo="false" renders the plain shadcn component.
| Component | What the goo does |
|---|---|
| Button | Drips off the edge, squishes on press, pulls taffy. |
| Spinner | Metaballs chase each other around a circle, merging and splitting. |
| Toggle | Pressing floods the button with goo. A toggle group's goo flows between items. New. |
| Switch | The thumb is a goo blob that throws itself across the track. |
| Checkbox | Checking drops goo into the box. |
| Radio group | The selected dot jumps to the next radio over a goo bridge. |
| Input | Focus runs goo around the field's border. Textarea too. New. |
| Slider | A liquid fill and a jelly thumb. |
| Progress | A liquid fill with a wobbling front and drips. |
| Select | The list blooms out of the selected item, and the check mark plops in. New. |
| Popover | Blooms open from a droplet and splashes all around. |
| Dropdown menu | Blooms open, and the highlight slides between items. |
| Tooltip | Blooms open, quick and small. |
| Tabs | The active indicator slides between tabs with momentum. |
| Accordion | The trigger row floods with goo and the content opens on a jelly spring. Collapsible too. New. |
| Dialog | The panel blooms in the middle of the screen, with an opt-in goo overlay. New. |
| Alert dialog | The dialog's bloom, calmer. New. |
| Sheet | Blooms out of the screen edge. New. |
| Drawer | A draggable drawer whose edge lags, sloshes, and splashes. New. |
| Toaster | Toasts drop in, merge when stacked, and drip away. |
| Page transition | A band of bubbly goo sweeps across the page on navigation. New. |
| Blob | Ambient goo for backgrounds. Soon. |
Blob comes last. It's also the performance stress test that decides whether a canvas renderer is needed.
Browser support
The last two versions of Chrome, Edge, Firefox, Safari, and iOS Safari. It has to feel good in Safari. If a filter is too slow there, that component falls back to static goo.