<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# NavigationRail

The vertical bar of the app's top-level pages on the start edge of a wide screen, as in a chat or mail app or an editor's activity bar: each item an icon over a short label, the current one with its `currentIcon`, a bar on the rail's edge and `aria-current="page"`. An item can carry a `count`, capped at "99+" on the badge and spoken in full, be a button for an app that switches views without its router (`onClick` without `href`), and sit after a `{ type: "separator" }`. A `header` (your app's mark) sits above the items and a `footer` (settings, the account) below them.

```tsx
import { NavigationRail } from "@/components/ouro/navigation-rail/navigation-rail";
```

## Example

```tsx
<NavigationRail
  label="Main"
  currentPath={pathname}
  header={<AppMark />}
  items={[
    { label: "Activity", href: "/activity", icon: <BellIcon />, currentIcon: <BellFilledIcon />, count: 3 },
    { label: "Chat", href: "/chat", icon: <ChatIcon />, currentIcon: <ChatFilledIcon /> },
    { label: "Calendar", href: "/calendar", icon: <CalendarIcon /> },
    { type: "separator" },
    { label: "Files", href: "/files", icon: <FolderIcon /> },
  ]}
  footer={<SettingsButton />}
/>
```

## Usage

The rail is one tab stop: Up and Down move between its items, wrapping, and Home and End go to the ends, while Tab moves on to the footer and the page. Items that do not fit the rail's height move, from the last, into a More menu at its end; the current item stays on the rail. Labels wrap to two lines between words; one still too long ends in an ellipsis and shows whole in a Tooltip, as every label does with `hideLabels`. The current item's bar grows in from its middle; with reduced motion it only fades.

Links render through `OuroProvider`'s `linkComponent`, so your router navigates. The rail fills its container's height and draws no surface of its own, so it sits on your app's frame.

## Use instead when

- Use `TabBar` instead for the bar at the bottom of a phone screen (hide the rail there with `className="max-sm:hidden"`), `Sidebar` for a column of labelled links in sections, and `Navbar` for a few links across the top.

## Props

Type: `NavigationRailProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string` |  | Layout only: placement and width, or `max-sm:hidden` where a `TabBar` takes over. Appearance classes warn in development. |
| `countLabel` | `string` | `"{count} new"` | What screen readers hear after an item's label when it has a `count`, with `{count}` for the number: "Activity, 5 new". |
| `currentPath` | `string` |  | The path of the page being shown, from your router (`useLocation().pathname`, or `usePathname()` in Next.js). The item whose `href` or `paths` match it, or else the longest one above it (`/chat` for `/chat/12`), gets `aria-current="page"` and the current look. |
| `footer` | `ReactNode` |  | Below the items, out of their way: a settings `Button` or an account `Menu`. |
| `header` | `ReactNode` |  | Above the items: your app's mark, or a workspace `Menu`. |
| `hideLabels` | `boolean` | `false` | Shows the icons alone, in a 56px rail; each item's label names it for screen readers and shows in a Tooltip on hover and keyboard focus. |
| `items` (required) | `readonly NavigationRailEntry[]` |  | The items, in order, with `{ type: "separator" }` between groups. Those that do not fit the rail's height move, from the last, into a More menu at its end; the current item stays on the rail. |
| `label` (required) | `string` |  | Names the navigation for screen readers ("Main"). It is not shown. |
| `moreLabel` | `string` | `"More"` | The label of the button that holds the items that do not fit. |
| `ref` | `Ref<HTMLElement>` |  | Reaches the `<nav>`. |

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `children`: Not rendered. The rail is `items`, `header` and `footer`.
- `collapsed`: Not a prop. `hideLabels` shows the icons alone.
- `links`: Not a prop. Ouro UI uses `items`: `<NavigationRail label="Main" items={[{ label, href, icon }]} />`.
- `onSelect`: Not a prop. Give the items their own `onClick`.
- `pathname`: Not a prop. Ouro UI uses `currentPath`: `<NavigationRail currentPath={pathname}>`.
- `selectedId`: Not a prop. Mark the shown view's item `current: true`, and switch views in each item's `onClick`.
- `value`: Not a prop. The current item follows `currentPath`, or an item's `current`.

## `className` is for layout only

Pass margins, width and grid placement (`mt-4`, `w-full`, `col-span-2`).

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (`hover:`, `sm:`) and any `!` are removed, it starts with `bg-`, `text-`, `border-`, `rounded-`, `shadow-`, `font-`, `ring-`, `from-`, `via-`, `to-`, `fill-` or `stroke-`, or is `border`, `rounded`, `shadow` or `ring`, or has a `dark:` variant. Text wrapping, overflow and table layout classes (`text-wrap`, `text-ellipsis`, `border-collapse`) are layout and do not warn.

Alignment classes (`text-center`) warn too: set alignment on a parent element.

## Types

### `NavigationRailButtonItem`

A button in a NavigationRail, for an app that switches views without its router: give the shown view's item `current`.

```ts
interface NavigationRailButtonItem extends NavigationRailItemBase {
  /** What the item does: show its view. */
  onClick: (event: MouseEvent<HTMLElement>) => void;
  /** Not with `onClick` alone. Give a link `href`; a button has none. */
  href?: never;
  /** Not on a button. A button is current by its `current` flag. */
  paths?: never;
}
```

### `NavigationRailEntry`

One entry in a NavigationRail's `items`: an item, or a separator between groups.

```ts
type NavigationRailEntry = NavigationRailItem | NavigationRailSeparator;
```

### `NavigationRailItem`

One item of a NavigationRail: a link (`href`) or a button (`onClick`).

```ts
type NavigationRailItem = NavigationRailLinkItem | NavigationRailButtonItem;
```

### `NavigationRailLinkItem`

A link in a NavigationRail: one of the app's top-level pages.

```ts
interface NavigationRailLinkItem extends NavigationRailItemBase {
  /** Where it goes. Internal paths go through `OuroProvider`'s `linkComponent` (your router's link). */
  href: string;
  /**
   * Other paths whose pages belong to this item, so it stays current there: a Chat item that
   * also owns `/people`. Each matches its own path and the pages under it.
   */
  paths?: readonly string[] | undefined;
  /** Called when the link is followed, before your router navigates. */
  onClick?: ((event: MouseEvent<HTMLElement>) => void) | undefined;
}
```

### `NavigationRailSeparator`

A short rule between groups of items, as Menu's `{ type: "separator" }` is.

```ts
interface NavigationRailSeparator {
  type: "separator";
}
```
