Skip to documentation content

Sidebar Nav

Navigate a chat product with primary destinations, a searchable list of past conversations, and a collapse to an icon rail.

sidebar-nav-demo

Overview

Sidebar Nav is the side navigation of a chat product. It has a short list of destinations, a New chat button, and the person's past conversations with a search field over them. It collapses to a rail of icons.

It renders the items and threads you pass and reports what was pressed. Routing and loading conversations are your application's work.

Anatomy

SidebarNav
  • HeaderYour workspace name or switcher, and the collapse button
  • DestinationsNew chat, then one row for each item
  • ChatsA search field and the list of past conversations
  • FooterYour own content, such as an account menu

Installing sidebar-nav brings Button along as a registry dependency.

Behavior

Collapsing

Collapsed, the nav keeps the collapse button and the destination icons. The header, the chat list, and the footer are left out, because the rail has no room for their text. Control it with collapsed and onCollapsedChange, or let it manage itself.

Searching chats

Typing filters the chats by title. When nothing matches, the list is replaced by a message that names the search. With no chats at all, the search field is left out and the list says so.

Accessibility

The component is a navigation landmark with a name. Every row is a button. The current destination is marked with aria-current="page", and the open conversation with aria-current.

The collapse button reports whether the nav is expanded. Collapsed, each destination keeps its label as its accessible name. The empty and no-match messages are statuses. With reduced motion, the width changes at once.

KeyAction
TabMove across the rows and the search field
Enter or SpaceOpen the focused destination or chat, or collapse the nav

Installation

npx honestui@latest add https://ai.honestui.com/r/sidebar-nav.json

Usage

import { SidebarNav } from "@/components/ai/sidebar-nav"

<SidebarNav
  header={<WorkspaceName />}
  items={[
    { id: "home", label: "Home", icon: <HomeIcon /> },
    { id: "files", label: "Files", icon: <FileIcon /> },
  ]}
  activeItemId={route.section}
  onNavigate={(itemId) => router.push(`/${itemId}`)}
  threads={chats}
  activeThreadId={route.chatId}
  onThreadSelect={(threadId) => router.push(`/chat/${threadId}`)}
  onNewChat={() => router.push("/chat/new")}
/>

The nav fills its parent's height, so place it in a full-height layout.

Examples

Collapsed, with no chats

The icon rail. Expand it to see the empty chat list.

sidebar-nav-collapsed

API reference

SidebarNav

Accepts native nav props beyond those listed.

PropTypeDefaultDescription
itemsSidebarNavItem[]RequiredEach has id, label, icon, and an optional badge.
activeItemIdstringNoneThe item for the current page.
onNavigate(itemId: string) => voidRequiredRuns when a destination is pressed.
threadsSidebarNavThread[]RequiredEach has id and title.
activeThreadIdstringNoneThe open conversation.
onThreadSelect(threadId: string) => voidRequiredRuns when a chat is pressed.
onNewChat() => voidNonePassing it adds the New chat button.
headerReactNodeNoneShown at the top while expanded.
footerReactNodeNoneShown at the bottom while expanded.
collapsedbooleanNoneThe collapsed state, when you control it.
defaultCollapsedbooleanfalseThe initial collapsed state.
onCollapsedChange(collapsed: boolean) => voidNoneRuns when the collapse button is pressed.
labelsPartial<SidebarNavLabels>EnglishLandmark, button, and field names, and the empty messages.