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

# Navbar

The bar across the top of an app: your brand, the main links and a few controls, with the current page marked `aria-current="page"`, and the link of the section it is in `aria-current="true"`, both underlined in the primary colour as in `FamilyBar`, distinct from hover and press highlights. A group of links (`{ label, links }`) opens a panel, as in `NavigationMenu`. Whenever the links do not fit, below 640px and on a narrow tablet, they collapse behind a menu button into a `Sheet` that slides in from the side, with each group under its name; the brand and `actions` stay in the bar. Links render through `OuroProvider`'s `linkComponent`, so your router navigates.

```tsx
import { Navbar } from "@/components/ouro/navbar/navbar";
```

## Example

```tsx
<Navbar
  label="Main"
  brand={<Link href="/">Spoonjoy</Link>}
  items={[
    { label: "Recipes", href: "/recipes" },
    { label: "Cookbooks", href: "/cookbooks" },
  ]}
  currentPath={pathname}
  actions={<Button href="/recipes/new">New recipe</Button>}
/>
```

## Usage

The phone menu opens once JavaScript has loaded (after hydration); the links are in the server HTML from 640px up. A tap on the menu button before then does nothing unless your app keeps it: this site's head script keeps a tap on any control React has not yet hydrated, shows the control pressed, and presses it again once it has (`site/src/early-input.ts` in the repository). Once the menu button shows, the sheet is built while the page is idle and kept, hidden, between opens, so a press only shows it.

Use `NavigationMenu` alone for a row of panels inside a page, and `Tabs` for views of one page. `StackedLayout` puts a Navbar above the page.

## Use instead when

- Use `Sidebar` instead for more than a handful of destinations, or sections of them.

## Props

Type: `NavbarProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `actions` | `ReactNode` |  | Controls at the end of the bar, at every width: a search button, an account `Menu`. |
| `brand` | `ReactNode` |  | Your logo or product name, at the start of the bar. Link it to the home page. |
| `className` | `string` |  | Layout only: margins, position (`sticky top-0`). Appearance classes warn in development. |
| `closeLabel` | `string` | `"Close"` | The label of that sheet's close button. |
| `currentPath` | `string` |  | The path of the page being shown, from your router (`useLocation().pathname`, or `usePathname()` in Next.js). The link to that path gets `aria-current="page"` and the current look. On a deeper page, the longest link above it, the section (`/recipes` for `/recipes/12`), gets the same look and `aria-current="true"`, so a screen reader hears one current page. |
| `items` (required) | `readonly NavbarItem[]` |  | The links, in order, and groups of links (`{ label, links }`), which open a panel in the bar. When they do not fit, as on a phone, they move into a sheet. |
| `label` (required) | `string` |  | Names the navigation for screen readers ("Main"). It is not shown. |
| `menu` | `ReactNode` |  | What the sheet behind the menu button holds in place of the `items` links, when a phone needs more than the bar, such as a section's own pages under its name, or a filter over a long list. It replaces them, so list the links they held too. It sits in the sheet's `nav`; mark the current page yourself (`aria-current="page"`). Choosing a link in it closes the sheet. Once the page has been idle it mounts, hidden, ahead of the first press (a press before then mounts it as it opens), and it mounts afresh the same way after each close, so each open starts with the state it first had. |
| `menuLabel` | `string` | `"Menu"` | The name of the button that opens the links below 640px, and the title of the sheet it opens. |
| `ref` | `Ref<HTMLElement>` |  | Reaches the rendered element. |

## 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 bar is `items`, `brand` and `actions`.
- `links`: Not a prop. Ouro UI uses `items`: `<Navbar label="Main" items={[{ label: "Recipes", href: "/recipes" }]} />`.
- `logo`: Not a prop. Ouro UI uses `brand`: `<Navbar brand={<Logo />}>`.
- `pathname`: Not a prop. Ouro UI uses `currentPath`: `<Navbar currentPath={pathname}>`.

## `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

### `NavbarGroup`

A group of links in a Navbar: a button that opens a panel in the bar, and a labelled group in the sheet.

```ts
interface NavbarGroup {
  /** The group's name, the button's text: "Recipes". */
  label: string;
  /**
   * The group's links, each with an optional `description`.
   */
  links: readonly NavbarLink[];
  /** Not with `links`. To link the section's own page, make it the group's first link. */
  href?: never;
}
```

### `NavbarItem`

One item of a Navbar: a link (`href`), or a group of links (`links`).

```ts
type NavbarItem = NavbarLink | NavbarGroup;
```

### `NavbarLink`

One link in a Navbar: in the bar, or in a group's panel.

```ts
interface NavbarLink {
  /** The link's text: "Recipes". */
  label: string;
  /** Where it goes. Internal paths go through `OuroProvider`'s `linkComponent` (your router's link). */
  href: string;
  /**
   * In a group: a line under the label in the bar's panel, "Everything you have saved."
   */
  description?: string | undefined;
  /**
   * Marks this link as the current page (`aria-current="page"`), when the Navbar's
   * `currentPath` cannot tell: a link whose page lives at another path.
   */
  current?: boolean | undefined;
  /** Not with `href`. An item is a link (`href`) or a group of links (`links`). */
  links?: never;
}
```
