Pill Nav
A minimal pill navigation whose highlight slides to the active item.
When the active item changes, the highlight pill slides smoothly between items with spring dynamics; icons, controlled and uncontrolled usage, and keyboard operation are all supported.
npx shadcn@latest add https://webberui.com/r/pill-nav.jsonPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<PillNav />
Installation
npx shadcn@latest add https://webberui.com/r/pill-nav.jsonOr, once registries are configured in components.json, install it as @webberui/pill-nav.
Usage
import { Compass, Home, Settings, User } from "lucide-react";
import { PillNav } from "@/components/ui/pill-nav";
<PillNav
defaultValue="Discover"
items={[
{ label: "Home", icon: Home },
{ label: "Discover", icon: Compass },
{ label: "Profile", icon: User },
{ label: "Settings", icon: Settings },
]}
/>;To use it as a row of links, add an href to each item and the component renders <a> elements:
<PillNav
items={[
{ label: "Docs", href: "/docs" },
{ label: "Blog", href: "/blog" },
]}
/>Controlled usage
Take over the active state with value and onValueChange:
const [tab, setTab] = React.useState("Home");
<PillNav
value={tab}
onValueChange={setTab}
items={[{ label: "Home" }, { label: "Discover" }]}
/>;Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | PillNavItem[] | — | The list of navigation items |
defaultValue | string | first item | Initially active item in uncontrolled mode (its label) |
value | string | — | The controlled active item (its label) |
onValueChange | (value: string) => void | — | Fires when the active item changes |
stiffness | number | 380 | Spring stiffness of the sliding highlight |
damping | number | 32 | Spring damping of the sliding highlight |
PillNavItem has the shape { label: string; href?: string; icon?: LucideIcon }. The label doubles as the unique identifier.
Accessibility
- The active item carries
aria-current="page", so assistive technology can identify the current position - Every item is a native
<button>or<a>, focusable with Tab, activatable with Enter, and carrying afocus-visiblefocus ring - When the user has "reduce motion" enabled at the system level, the highlight switches instantly with no sliding animation
Customization
The highlight and focus ring colors are exposed as --wb-* CSS variables and can be overridden through className:
--wb-pill-active-bg: background of the active pill--wb-pill-active-fg: text color of the active item--wb-pill-ring: color of thefocus-visiblefocus ring