A gooey navigation bar that separates the selected item from the group.
Click an item to lift it out of the bar; the rest close back into one piece behind it.
Options you can pass to customize this component.
items*(string | { label: string; href?: string; icon?: ReactNode })[]Nav entries. A string is a button, an object with href is a link, and icon renders before the label.
valuenumberIndex of the selected item. Pass it to control the nav yourself; leave it out and the nav follows the url when the items have hrefs, and its own state otherwise.
defaultValuenumberIndex the nav starts on when it is uncontrolled. Ignored once value is passed, and ignored when an item href matches the current url.
onChange(index: number) => voidFires with the index of the item that was clicked.
sizexssmmdlgScale of the bar. Sets the label padding, text size and icon size, and picks the matching separation and radius so the shape stays in proportion. Use xs on phones, where it fits a 360px screen.
activeColorstringFill of the selected tile. The unselected bar follows the theme instead, light grey on light and near black on dark.
activeLabelColorstringLabel color of the selected item. Set it when a light activeColor leaves white text unreadable.
separationnumberGap in pixels that opens on each side of the selected item, which is what pushes the rest of the bar aside. Defaults to the size: 14 (xs), 16 (sm), 20 (md), 24 (lg).
radiusnumberCorner radius of the tiles in pixels. Only the outer corners of the bar and the corners along an open gap use it; a closed seam sits at 0 so the tiles read as one shape. Defaults to the size: 8 (xs), 10 (sm), 12 (md), 14 (lg).
classNamestringExtra classes merged onto the root element (data-slot="gooey-nav"). The bar sizes to its content and never wraps, so add an overflow container here if it can outgrow its parent.
npx shadcn@latest add swamimalode07/rare-ui/gooey-nav"use client"import { GooeyNav } from "@/components/ui/gooey-nav"export function Demo() {return (// hrefs make it track the url on its own, no value needed<GooeyNavitems={[{ label: "Home", href: "/", icon: <HouseIcon /> },{ label: "Changelog", href: "/changelog" },{ label: "About", href: "/about" },]}/>)}// strings render buttons instead, for a segmented control:// <GooeyNav items={["Day", "Week", "Month"]} onChange={setRange} />// size is a single value, so step it down yourself on small screens:// <GooeyNav items={items} size={useIsMobile() ? "xs" : "md"} />
Click the code icon in the top-right corner to view the source code.
Most components here are recreations of great work from around the web. I don't claim to be the original creator - this is my attempt to reverse-engineer, replicate, and often add a few extra features. I've tried to credit everyone; if I missed someone, let me know.
1