Components
PreviousNext

Gooey Filter

A filter component that creates a gooey effect on the background for fluid tab panels and rounded-at-all-corners interfaces.

Loading...
"use client";
 
import * as React from "react";
 
import { Button } from "@/components/ui/button";
import {
  GooeyTabPanel,
  type GooeyTabItem,
} from "@/components/gooey-filter";
 
const TABS: GooeyTabItem[] = [
  {
    id: "2024",
    label: "2024",
    items: [
      "learning-to-meditate.md",
      "spring-garden-plans.md",
      "travel-wishlist.md",
      "new-coding-projects.md",
    ],
  },
  {
    id: "2023",
    label: "2023",
    items: [
      "year-in-review.md",
      "photography-log.md",
      "recipe-collection.md",
      "side-project-notes.md",
    ],
  },
  {
    id: "2022",
    label: "2022",
    items: [
      "moving-checklist.md",
      "conference-talk.md",
      "book-highlights.md",
      "weekend-hikes.md",
    ],
  },
  {
    id: "2021",
    label: "2021",
    items: [
      "first-blog-post.md",
      "learning-rust.md",
      "home-office-setup.md",
      "morning-routine.md",
    ],
  },
];
 
export default function GooeyFilterDemo() {
  const [enabled, setEnabled] = React.useState(true);
 
  return (
    <div className="flex w-full flex-col items-center gap-6 bg-transparent px-8 py-10">
      <div className="flex w-full max-w-xl justify-start">
        <Button
          type="button"
          variant="outline"
          size="sm"
          onClick={() => setEnabled((value) => !value)}
        >
          {enabled ? "Disable filter" : "Enable filter"}
        </Button>
      </div>
 
      <GooeyTabPanel tabs={TABS} enabled={enabled} defaultTab="2024" />
    </div>
  );
}

Installation

bunx --bun shadcn@latest add "https://quatadahnasdami.xyz/r/gooey-filter.json"

Usage

import { GooeyFilter, GooeyTabPanel } from "@/components/gooey-filter";
const tabs = [
  {
    id: "2024",
    label: "2024",
    items: ["learning-to-meditate.md", "spring-garden-plans.md"],
  },
  {
    id: "2023",
    label: "2023",
    items: ["year-in-review.md", "photography-log.md"],
  },
];
 
<GooeyTabPanel tabs={tabs} defaultTab="2024" />

Filter only

Use GooeyFilter on any container that should merge adjacent shapes:

<GooeyFilter id="goo" strength={12} />
 
<div style={{ filter: "url(#goo)" }} className="flex gap-4">
  <div className="size-20 rounded-full bg-rose-500" />
  <div className="size-20 rounded-full bg-emerald-500" />
</div>

API Reference

GooeyFilter

PropTypeDefaultDescription
idstring"goo"Filter id referenced by url(#id).
strengthnumber10Goo intensity — higher values merge more.
classNamestring-Classes for the hidden filter element.

GooeyTabPanel

PropTypeDefaultDescription
tabsGooeyTabItem[]-Tab definitions with labels and list content.
defaultTabstring-Initially selected tab id.
enabledbooleantrueToggle the goo filter on or off.
strengthnumber10Passed through to GooeyFilter.
filterIdstring-Custom filter id when using multiple instances.
onTabChange(id) => void-Fires when the active tab changes.
classNamestring-Root container classes.
panelClassNamestring-Background surface classes for tab and panel.

GooeyTabItem

PropTypeDescription
idstringUnique tab identifier.
labelstringTab button label.
itemsstring[]Simple list rows rendered inside the panel.
contentReact.ReactNodeCustom panel content instead of a list.

Browser support

The goo effect relies on filters applied through CSS. It works in Chromium and Firefox. Safari support is limited — use the enabled prop to fall back to a standard rounded panel when needed.