Gooey Nav React component for Tailwind CSS v4
v1.0.1Updated in 1.2.1
A React navigation bar with a gooey effect: the selected item stretches away from the group.
Click an item to lift it out of the bar. A gap opens on each side of it, a stretchy neck thins and snaps as the tiles part, and the rest close back into one piece behind it. With hrefs, the nav follows the current URL on its own. On phones the demo docks it under a page as a stacked, full width tab bar.
Gooey Nav is a free React component in the React navigation components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add gooey-nav, together with Motion presets and UIProvider and the npm package motion.
Add to a project
Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add gooey-navUsage
Import GooeyNav from @/components/ui/gooey-nav.
"use client"
import { House } from "lucide-react"
import { GooeyNav } from "@/components/ui/gooey-nav"
export function Demo() {
return (
// hrefs make it track the url on its own, no value needed
<GooeyNav
items={[
{ label: "Home", href: "/", icon: <House /> },
{ 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"} />
// or dock it under a phone screen like a tab bar:
// <GooeyNav items={items} size="sm" layout="stacked" fullWidth />Props
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.
sizedefault"md""xs" | "sm" | "md" | "lg"Scale 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.
layoutdefault"inline""inline" | "stacked"Inline puts the icon beside the label. Stacked puts it above, like a phone tab bar, which keeps four items inside a 360px screen at sm.
fullWidthdefaultfalsebooleanStretches the bar across its container and shares the width between the items, for a bar docked to the bottom of a screen.
activeColordefault"#FC4C01"stringFill of the selected tile. The unselected bar follows barColor.
activeLabelColordefault"#ffffff"stringLabel color of the selected item. Set it when a light activeColor leaves white text unreadable.
barColordefault""stringAny CSS color for the unselected tiles and the necks between them. Empty follows the theme: #F4F4F9 light, #262626 dark.
labelColordefault""stringAny CSS color for the unselected labels. Empty uses #6E6D7A light, #9B9AA7 dark.
separationdefault20numberGap in pixels that opens on each side of the selected item, which is what pushes the rest of the bar aside. Leave it out to follow the size: 14 (xs), 16 (sm), 20 (md), 24 (lg). A value you pass overrides the size preset.
radiusdefault12numberCorner 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. Leave it out to follow the size: 8 (xs), 10 (sm), 12 (md), 14 (lg). A value you pass overrides the size preset.
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.
defaultValuedefault0numberIndex 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.
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 around it if it can outgrow its parent.
Parts
Examples
Segmented control
Plain strings render buttons, so the bar works as a controlled segmented control.
Light accent
Pair a light activeColor with a dark activeLabelColor to keep the label readable.
App tab bar
layout stacked puts icons over labels and fullWidth spreads the tabs across the screen, here in blue.
Files
- components/ui/gooey-nav.tsx
FAQ
Is the React Gooey Nav component free?
Yes. The source is free and needs no account: copy it from the Code tab or install it with the CLI.
How do I install Gooey Nav?
Run npx wingo-ui@latest add gooey-nav. It also adds the Wingo UI items it builds on (Motion presets and UIProvider) and the npm package motion. With shadcn, run npx shadcn@latest add https://wingo-ui.com/r/gooey-nav.json.
How does Gooey Nav behave on phones?
On phones the demo docks it under a page as a stacked, full width tab bar.
See also
More React navigation components
Articles using this component
- Magic UI Alternatives: 5 Animated React Libraries Compared
Comparisons and alternatives11 min read