WebberUI

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.

Loading preview…
npx shadcn@latest add https://webberui.com/r/pill-nav.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

380
32
<PillNav />

Installation

npx shadcn@latest add https://webberui.com/r/pill-nav.json

Or, 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

PropTypeDefaultDescription
itemsPillNavItem[]The list of navigation items
defaultValuestringfirst itemInitially active item in uncontrolled mode (its label)
valuestringThe controlled active item (its label)
onValueChange(value: string) => voidFires when the active item changes
stiffnessnumber380Spring stiffness of the sliding highlight
dampingnumber32Spring 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 a focus-visible focus 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 the focus-visible focus ring

On this page