Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Navigation

Sidebar

Navigation

Sidebar React component for Tailwind CSS v4

Scroll ProgressSteps
Live props
State
defaultCollapsed
currentPath
persistKey
loading
Behavior
filter
filterPlaceholder
filterShortcut
defaultFilterValue
collapsible
showToggle
shortcut
itemShortcuts
tooltips
flyouts
Appearance
variant
activeStyle
size
tone
color
Layout
width256px
mode
Code
import { Sidebar } from "@/components/ui/sidebar"

<Sidebar />
  1. Home
  2. Components
  3. Navigation
  4. Sidebar
Pro

Sidebar React component for Tailwind CSS v4

v1.0.0·Added in 1.0.0

A React sidebar for admin apps: grouped links with icons, nested sections, badges, a sliding active pill, an icon rail and a filter.

Click a link and the active pill slides to it on a smooth spring; parents fold their children open with a chevron (a parent with its own page gets a separate chevron button), and collapsible group labels fold whole groups. Cmd/Ctrl+B or the footer button collapses it to a 64px icon rail: labels turn into tooltips, badges into dots, and parents open their children as a menu to the side. With the filter on, typing hides what does not match, opens the sections that do and bolds the matched letters; Escape clears it and arrow-down jumps into the list. An item's shortcut (Home has one in the demo) opens its page from anywhere. With the keyboard, Up / Down move between rows, Home / End jump, Right opens a parent (or steps into it) and Left closes it (or steps back to the parent). Rows darken while pressed and are 44px on touch screens; inside an app shell's phone drawer (mode="sheet") the rows grow and tapping a link closes the drawer. Collapsed and open sections are remembered with persistKey.

Sidebar is a Pro 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 sidebar, together with UIProvider, Avatar, Badge, Button, Dropdown Menu and 12 more and the npm packages motion and lucide-react.

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 sidebar

Sidebar is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans

Usage

Import Sidebar from @/components/ui/sidebar.

import { ChartColumn, FileText, Handshake, Inbox, LayoutDashboard, LifeBuoy, Package, Settings, ShoppingCart, Users } from "lucide-react"
import { Sidebar, type SidebarNavGroup } from "@/components/ui/sidebar"

const groups: SidebarNavGroup[] = [
  {
    items: [
      { label: "Home", href: "/", icon: <LayoutDashboard /> },
      { label: "Inbox", href: "/inbox", icon: <Inbox />, badge: 4 },
    ],
  },
  {
    label: "Sales",
    items: [
      { label: "Clients", href: "/clients", icon: <Users /> },
      { label: "Offers", href: "/offers", icon: <Handshake />, badge: 12 },
      {
        label: "Invoices",
        href: "/invoices",
        icon: <FileText />,
        items: [
          { label: "Issued", href: "/invoices/issued" },
          { label: "Paid", href: "/invoices/paid" },
          { label: "Overdue", href: "/invoices/overdue", badge: 3 },
        ],
      },
    ],
  },
  {
    label: "Operations",
    collapsible: true,
    items: [
      { label: "Products", href: "/products", icon: <Package /> },
      { label: "Orders", href: "/orders", icon: <ShoppingCart /> },
      { label: "Reports", href: "/reports", icon: <ChartColumn /> },
    ],
  },
  {
    label: "Account",
    items: [
      { label: "Settings", href: "/settings", icon: <Settings /> },
      { label: "Help", href: "https://example.com/help", icon: <LifeBuoy /> },
    ],
  },
]

export function AppSidebar({ pathname }: { pathname: string }) {
  return (
    <Sidebar
      groups={groups}
      currentPath={pathname}
      persistKey="crm-sidebar"
      filter
      user={{ name: "Emma Carter", email: "emma.carter@northwind.com", avatar: "/demo/ana-pop.jpg", plan: "Pro" }}
      className="h-dvh"
    />
  )
}

Props

  • groups
    SidebarNavGroup[]

    The navigation: { id?, label?, items, collapsible?, defaultOpen? } per group. Items are NavItem ({ label, href, icon, activeIcon, badge, shortcut, keywords, external, disabled, match, onSelect, items }), nested one level deep.

  • items
    SidebarNavItem[]

    One unlabeled group, for small apps. Ignored when groups is set.

  • header
    ReactNode

    Above the navigation: a WorkspaceSwitcher variant="card" or a logo. It adapts to the rail through the group/sidebar CSS contract (data-collapsed="true").

  • footer
    ReactNode

    Below the navigation, before the collapse button: a UserMenu trigger="card". Replaces the user card.

  • user
    { name: string; email?: string; avatar?: string; plan?: ReactNode }

    A simple user card in the footer when there is no footer; onUserClick makes it a button.

  • onUserClick
    (event: MouseEvent<HTMLButtonElement>) => void

    Makes the user card a button.

  • defaultCollapseddefault false
    boolean

    Starts as the 64px icon rail. Use collapsed + onCollapsedChange to control it; inside an AppShell the shell owns it.

  • collapsed
    boolean

    Controlled collapsed state.

  • onCollapsedChange
    (collapsed: boolean) => void

    Fires when the rail opens or closes (button, shortcut).

  • value
    string

    The active item's key (its id, else href, else label): controlled. Without it the active item follows currentPath, else the sidebar keeps its own (defaultValue, default the first enabled item).

  • defaultValue
    string

    The first active item when neither value nor a path is known.

  • onValueChange
    (key: string, item: SidebarNavItem) => void

    Fires on every activation, in all three modes.

  • currentPathdefault ""
    string

    The path the active item is matched against (the longest matching href wins). Default: the LinkProvider's. The playground's pretend router provides it.

  • persistKeydefault ""
    string

    Remembers collapsed (standalone) and the open sections in local storage under `${persistKey}-collapsed` and `${persistKey}-open`. Empty keeps them in memory.

  • loadingdefault false
    boolean

    Skeleton rows (icon + line) in place of the items, with aria-busy on the nav.

  • filterdefault false
    boolean

    A filter field above the navigation. Matches labels and keywords ignoring case and diacritics, opens the sections that hold a match and bolds the matched letters. On the rail it becomes a search button that expands the sidebar.

  • filterPlaceholderdefault "Search"
    string

    The filter's placeholder.

  • filterShortcutdefault ""
    string

    A key combo (mod+k notation) that focuses the filter from anywhere, expanding the rail first. Shown as a hint in the field.

  • defaultFilterValuedefault ""
    string

    Starts the filter with a query (uncontrolled), e.g. a search carried over from another page.

  • onFilterValueChange
    (value: string) => void

    Fires as the filter text changes.

  • filterValue
    string

    The filter text, controlled.

  • variantdefault "sidebar"
    "sidebar" | "floating" | "inset"

    sidebar: flush, a hairline on the end edge. floating: a raised rounded panel 8px off the edges. inset: no edge and no fill, on the app shell's tint.

  • activeStyledefault "soft"
    "soft" | "raised" | "bar"

    The active row: a tinted pill, a raised white pill (best on floating or tinted sidebars), or a 3px bar on the start edge over a light tint.

  • sizedefault "md"
    "sm" | "md"

    Rows 32 / 36px with 13 / 14px text; 44px on touch screens either way.

  • widthdefault 256
    number

    Expanded width in px (160 to 480). The rail is always 64px; the width animates between the two.

  • tonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    Colors the active indicator, the active row's text and its badge. Neutral is a gray pill with black / white text.

  • colordefault ""
    string

    Any CSS color for the active indicator; replaces the tone.

  • collapsibledefault "icon"
    "icon" | "none"

    icon: it can become the 64px rail (button and shortcut). none: always expanded, no toggle.

  • showToggledefault true
    boolean

    The collapse button at the end of the footer, with a tooltip showing the shortcut.

  • shortcutdefault "mod+b"
    string

    Toggles the rail from anywhere when the sidebar stands alone (mod is Cmd on Apple devices, Ctrl elsewhere). Inside an app shell the shell binds its own. Empty turns it off.

  • itemShortcutsdefault true
    boolean

    Binds each item's shortcut (mod+k notation, shown as a hint on hover and in rail tooltips) to open that page from anywhere, with aria-keyshortcuts on the row. Off leaves them as hints. Sheet mode never binds them (the desktop copy does).

  • tooltipsdefault true
    boolean

    On the rail every row shows its label (and shortcut) in a tooltip to the side; expanded, only labels cut off by the width do.

  • flyoutsdefault true
    boolean

    On the rail a parent opens its children as a menu to the side (a bottom sheet on phones). Off, clicking a parent expands the sidebar with that parent open.

  • modedefault "rail"
    "rail" | "sheet"

    rail: the desktop column, collapsible. sheet: the content of a phone drawer: never collapsed, 44px rows at 15px, no toggle, and a tap on a link closes the app shell's drawer (the app shell renders its drawer copy this way).

  • linkComponent
    (props: LinkComponentProps) => ReactNode

    The router link for this sidebar; default the LinkProvider's, else a plain <a>.

  • labels
    { sidebar?; navigation?; filter?; noResults?: (query) => string; collapse?; expand?; toggleGroup?: (label) => string; clearFilter?; loading? }

    Every string, English by default: "Sidebar", "Main", "Filter navigation", "Nothing matches “…”", "Collapse sidebar", "Expand sidebar", "Toggle …", "Clear filter", "Loading navigation".

  • classNames
    Partial<Record<"inner" | "header" | "filter" | "content" | "group" | "groupLabel" | "list" | "item" | "link" | "icon" | "label" | "badge" | "indicator" | "sublist" | "empty" | "footer" | "toggle" | "userCard", string>>

    Extra classes for the inner parts.

  • className
    string

    Extra classes for the <aside>. Set --sidebar-bg to change its surface.

  • children
    ReactNode

    Replaces the generated groups inside the scrolling nav (SidebarGroup / SidebarItem).

Parts

  • SidebarRoot

    component

    The <aside> with the state (collapsed, active item, open sections, filter) for the parts below. Takes every Sidebar prop except header, footer, user, filter* and showToggle. Props: SidebarRootProps.

  • SidebarHeader

    component

    The top area (p-3); a hairline appears under it when the list scrolls. Takes div props.

  • SidebarFooter

    component

    The bottom area; a hairline appears while more of the list is below, and it stacks vertically on the rail. Takes div props.

  • SidebarContent

    component

    The scrolling <nav> with fading edges and the arrow-key navigation. Renders the root's groups when it has no children. Takes nav props.

  • SidebarGroup

    component

    One labelled group (a fold-away label when collapsible), for hand-built layouts. Props: { group: SidebarNavGroup; index?: number; children?: ReactNode }.

  • SidebarItem

    component

    One row with its nested children. Props: { item: SidebarNavItem; index?: number; depth?: number; parentKey?: string }.

  • SidebarFilter

    component

    The filter field (a search button on the rail). Props: { placeholder?: string; shortcut?: string } & input props.

  • SidebarToggle

    component

    The collapse button with its tooltip; renders nothing in sheet mode or when collapsible is none. Props: ButtonProps.

  • SidebarUserCard

    component

    Avatar, name, plan and email; the avatar alone on the rail. A button with onClick or interactive (a menu trigger). Props: { user: SidebarUser; trailing?: ReactNode; interactive?: boolean } & button props.

  • useSidebar

    hook

    The sidebar's state for anything rendered inside it. Signature: () => { collapsed; setCollapsed; toggle; mode; activePath }.

  • SidebarNavItem

    type

    One link, the shared NavItem: id, label, textValue, href, icon, badge, description, disabled, external, match ("exact" | "prefix"), onSelect, nested items, keywords for the filter and shortcut.

  • SidebarNavGroup

    type

    A group of items under an optional label: id, label, items, collapsible (the label folds the group) and defaultOpen.

  • SidebarUser

    type

    The footer user card: name, email, avatar and plan.

  • UseSidebarResult

    type

    What useSidebar returns: collapsed, setCollapsed, toggle, mode and activePath (the active item with its parents, or null).

Examples

The icon rail

defaultCollapsed: tooltips to the side, dots for badges, and Invoices and Settings open their pages as a flyout menu.

Filter

“rest” finds Invoices › Overdue: the section opens and the match is bold. Press F to focus it, Escape to clear.

Floating with a raised pill

variant="floating" + activeStyle="raised" on a tinted page, the white pill sliding between rows.

Bar indicator in the brand tone

activeStyle="bar" + tone="brand": a 3px bar on the start edge that runs along the guide line into nested rows.

Phone drawer (sheet mode)

mode="sheet" inside a drawer: 44px rows at 15px, no toggle, and tapping a link closes the drawer.

Loading

loading renders skeleton rows (icon + line) with aria-busy.

External links and “New” badges

Any node works as a badge; external links get a trailing arrow and a new tab.

Dependencies

motionlucide-reactui-configavatarbadgebuttondropdown-menukbdskeletontooltipuse-controllable-stateuse-media-queryuse-persisted-stateuse-scroll-edgesuse-shortcutmotionnavigationtext-matchtones

Files

  • components/ui/sidebar.tsx

FAQ

Is the React Sidebar component free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install Sidebar?

Run npx wingo-ui@latest add sidebar. It also adds the Wingo UI items it builds on (UIProvider, Avatar, Badge, Button, Dropdown Menu and 12 more) and the npm packages motion and lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/sidebar.

See also

App ShellHook SidebarBounce SidebarTopbarNavigationlibDropdown Menu

Used in

App ShellAdmin Shell

More React navigation components

Back To TopCommand MenuGlobal SearchNav TabsPaginationSteps
All 19 React navigation components

Articles using this component

  • Shadcn Sidebar Mobile: Fix the Sheet and Add a Tab Bar

    Mobile UI in React · Nov 5, 2026 · 9 min read

  • Nextjs Admin Dashboard Tutorial: 5 Screens, Phone-Ready

    Build it: screens and apps · Oct 9, 2026 · 23 min read

  • React Bottom Navigation Bar in Next.js: Safe Areas, Badges

    Mobile UI in React · Oct 9, 2026 · 8 min read

PreviousScroll ProgressNext Steps
  • HomeCtrl+Shift+H
  • Inbox4
Sales
  • Clients
  • Offers12
  • Invoices
    • Issued
    • Paid
    • Overdue3
  • Products
  • Orders
  • Reports
Account
  • Help
/invoices/overdue

Overdue invoices

3 invoices, $24,180.00 in total

  • #2026-0398Keystone Builders · due Sep 2, 2026
    $15,400.00
  • #2026-0391Greenleaf Pharmacy · due Aug 28, 2026
    $6,120.00
  • #2026-0385Dental Art Clinic · due Aug 20, 2026
    $2,660.00
Collapse
CtrlBControl B
Filter key
none
Placeholder
“Search”
Starts with
empty
Home
CtrlShiftHControl Shift H
Tooltips
on
Flyouts
on
Persisted as
not persisted