Components / AI interface

SidebarNav

Collapsible workspace and chat navigation with gliding hover states.

Install

npx shadcn@latest add https://irisui.dev/r/sidebar-nav.json
import SidebarNav from "@/components/iris/sidebar-nav/sidebar-nav";
Registry item sidebar-navBrings in foundationRegistry JSON

Preview

SidebarNav

A collapsible app sidebar with a workspace switcher, primary navigation, searchable chat history and a footer call-to-action, all sharing a gliding hover highlight.

When to use

  • Use it as the left rail of an assistant or agent workspace that lists recent chats.
  • Use it when the rail needs to collapse to 52px icons while keeping icon alignment.
  • Not for marketing or site navigation — use SiteHeader. Not for a hierarchical file tree — use TreeView.

Usage

import SidebarNav from "@/components/iris/sidebar-nav/sidebar-nav";

h(
  "div",
  { style: { height: "100vh", display: "flex" } },
  h(SidebarNav, {
    fill: true,
    recents: [
      { id: "workload", label: "Desk workload summary" },
      { id: "ferry", label: "Ferry strike quick brief", prompt: "Draft a quick brief on the ferry strike" },
    ],
    activeTitle: "Desk workload summary",
    onPick: (id, label, prompt) => openChat(id),
    onNewChat: () => startChat(),
    footerLabel: "Upgrade",
  }),
);

Props

Prop Type Default Description
recents { id: string; label: string; prompt?: string }[] 8 demo chats Chat history rows, filtered by the built-in chat search.
activeTitle string | null internal demo state Controlled selected chat, matched by label. Leave it undefined for internal selection.
onPick (id, label, prompt?) => void — Called when a chat row is clicked.
onNewChat () => void — Called by "New chat" (and by the footer button when onFooterClick is not set).
activeNav string internal Controlled primary-nav key ("home", "invite", or "chats" for none).
onNavigate (key: string) => void — Called when a primary-nav row is chosen.
footerLabel / footerIcon / onFooterClick string / ReactNode / () => void "Upgrade" / — / — Footer call-to-action button.
fill boolean false true uses the parent's full height. The default is a fixed 600px.
className string "" Extra classes on the <aside>.
variant string — Accepted for gallery parity. It has no effect.

Notes

  • The workspace name ("Aegean evening desk", an ErmisAI newsroom), its newspaper icon and the "Invite members 3/5" row are hard-coded, as is the workspace switcher menu. Long workspace names truncate with an ellipsis.
  • Icons come from lucide-react.
  • Collapsing sets data-sidebar-collapsed on the <aside>; rows narrow to 36px and their text fades out with a small leftward shift, so every icon stays centred in the 52px rail.
  • The <aside> is labelled "Workspace navigation". The collapse and expand controls have aria-labels and are removed from the tab order while hidden. Chat search opens from the magnifier, and Escape closes it.
  • The sidebar has no background of its own. It sits on whatever surface you place it on (the preview uses --canvas).
  • Width animates between 224px and 52px. The bundle's global reduced-motion rule shortens this to near zero.
  • Reads --hover-2, --field, --line, --line-strong, --ink, --ink-2 and --ink-3.