Skip to content
zedkit
@zedtech/zedkit-ui

SidebarNavItem

One row for status, title, recency (`meta`), quantity (`count`), and active; groups collapse with native disclosure.

alpha@zedtech/zedkit-ui

Wraps: lucide-react, details

View props table
Who is it for?
Developers rendering a sidebar run list, inbox, or queue.
When should I use it?
Inside `AppShell` sidebar (or any list) when each row needs status + title + optional meta/count. For a destination, pass `asChild` with a link.
When should I pick something else?
For site chrome or marketing nav — use `Faq` or header links; for the page frame — use AppShell.

Use it

Examples import from the package. With copied source, import from @/components/ui/sidebar-nav instead.

Simple
import { SidebarNavItem, StatusDot } from "@zedtech/zedkit-ui";
<nav aria-label="Runs">
  <ul>
    <li>
      <SidebarNavItem status={<StatusDot tone="success" />} meta="2m ago" count="3">
        Nightly
      </SidebarNavItem>
    </li>
  </ul>
</nav>

Active

import { SidebarNavItem } from "@zedtech/zedkit-ui";
<SidebarNavItem asChild active>
  <a href="/runs/1">Nightly</a>
</SidebarNavItem>

Group

import { SidebarNavGroup, SidebarNavItem } from "@zedtech/zedkit-ui";
<SidebarNavGroup label="Runs">
  <SidebarNavItem>Nightly</SidebarNavItem>
  <SidebarNavItem>Staging</SidebarNavItem>
</SidebarNavGroup>

Kit not installed yet?

You get
Every component from one import, with the theme tokens included. Updates arrive with your package manager.
You need
  • React 19 and Tailwind CSS 4, for example a Next.js app created with the Tailwind option.
  1. Install

    Terminal
    pnpm add @zedtech/zedkit-ui @fontsource-variable/inter @fontsource-variable/space-grotesk
  2. Load the styles

    Tailwind does not scan node_modules, so the @source line points it at the kit's class names. The path is relative to this file.

    src/app/globals.cssReplace the contents
    @import "tailwindcss";
    @import "@zedtech/zedkit-ui/styles.css";
    @source "../../node_modules/@zedtech/zedkit-ui/src/**/*.{ts,tsx}";
    @source not "../../node_modules/@zedtech/zedkit-ui/src/**/*.test.*";
    
  3. Pick a look

    Set data-identity="glass" on <html> so the finished app matches the site. Fresh app: replace src/app/layout.tsx. Existing app: merge, and keep ThemeProvider and other providers.

    src/app/layout.tsxReplace the contents
    import "./globals.css";
    import "./fonts";
    
    export default function RootLayout({ children }: { children: React.ReactNode }) {
      return (
        <html lang="en" data-identity="glass">
          <body>{children}</body>
        </html>
      );
    }
    
  4. Load the fonts

    The Glass look uses Inter and Space Grotesk; these imports self-host them.

    src/app/fonts.tsCreate the file
    import "@fontsource-variable/inter";
    import "@fontsource-variable/space-grotesk";
    
  5. Import and render

    src/app/page.tsxReplace the contents
    import { SidebarNavItem, StatusDot } from "@zedtech/zedkit-ui";
    
    export default function Page() {
      return (
        <main className="px-page-gutter py-section-sm">
          <nav aria-label="Runs">
            <ul>
              <li>
                <SidebarNavItem status={<StatusDot tone="success" />} meta="2m ago" count="3">
                  Nightly
                </SidebarNavItem>
              </li>
            </ul>
          </nav>
        </main>
      );
    }
    

Package version 2.0.1.

Props

Prop

Type

Show inherited HTML attributes

Standard attributes from the underlying element. See MDN.

Prop

Type

Accessibility

Default host is a native button (type="button") with min-h-target (44px on a phone); for navigation, pass asChild with a link. asChild merges onto a single host element (a string, Fragment, or several children fall back to a button). active sets aria-current="page" on a link host and aria-current="true" on the button host (override via props). The title is the accessible name; status and trail stay aria-hidden by design — put those facts in the title if they must be announced. Item titles and group labels truncate. Group is native details/summary (Enter/Space, find-in-page). The chevron is aria-hidden. Callers own landmarks and list structure (nav wrapping ul/li). Disabled asChild hosts keep href and tab order; click, Enter, and Space are cancelled.

Troubleshooting

`asChild` needs one host element (a link for navigation) — a string, Fragment, or several children fall back to a button, they do not throw. `disabled` on `asChild` becomes `aria-disabled` (not `disabled` or `type`) and cancels click/Enter/Space; href and tab order stay. Status/meta/count wrappers omit when those props are missing (`status={0}` and `count={0}` still render). `meta` is recency or secondary text; `count` is a quantity; both sit in one trail as separate spans. Groups start closed; pass `open` to expand. Pass `StatusDot` / `Badge` in; this module does not import them. Do not wrap rows in a kit `<nav>` — keep `nav`/`ul`/`li` on the caller.

On this page