# Nav Bar
> A responsive, horizontal navigation bar designed for primary app navigation.

## Import

```js
import { NavBar } from '@gemini-suite/vera-react';

// you may also access NavBar's context via hook:
// import { useNavBarContext } from '@gemini-suite/vera-react';
```

NavBar is a compound component that consists of multiple parts.

- `Navbar.Root`: A container for all the parts of the nav bar.
- `Navbar.Item`: An item for a single action.
- `Navbar.ItemLabel`: An optional wrapper for item's textual label.

## Examples

### Basic

`NavBar` is a horizontal navigation bar that should be used to move between major areas of your application.

<Callout variant="tip">

To alternate among related views within the same context, consider using [Tabs
component](/components/tabs) instead.

</Callout>

It is a responsive component that adapts to the available horizontal space.
When there is not enough space, nav bar items that don't fit will be added into an overflow disclosure menu.
The active item will remain visible to communicate the current context to the user.

<Callout variant="tip">
  Resize preview box below to notice responsive behavior of the component.
</Callout>

```jsx resizable=true
<NavBar.Root defaultActiveItem="home" aria-label="Main navigation">
  <NavBar.Item id="home">{'Home'}</NavBar.Item>
  <NavBar.Item id="dashboard">{'Dashboard'}</NavBar.Item>
  <NavBar.Item id="statistics">{'Statistics'}</NavBar.Item>
  <NavBar.Item id="analytics">{'Analytics'}</NavBar.Item>
  <NavBar.Item id="deployments">{'Deployments'}</NavBar.Item>
</NavBar.Root>
```

### Sizes

`NavBar` comes in two sizes: `medium` and `small`. By default, it uses `medium` size.

```jsx resizable=true
<Flex flow="column" gap="spacingXl">
  <NavBar.Root
    defaultActiveItem="dashboard"
    aria-label="Main navigation in medium size"
  >
    <NavBar.Item id="dashboard">{'Dashboard'}</NavBar.Item>
    <NavBar.Item id="portfolio">{'Portfolio'}</NavBar.Item>
    <NavBar.Item id="market">{'Market'}</NavBar.Item>
    <NavBar.Item id="capacity">{'Capacity'}</NavBar.Item>
    <NavBar.Item id="trade-results">{'Trade results'}</NavBar.Item>
  </NavBar.Root>
  <NavBar.Root
    size="small"
    defaultActiveItem="dashboard"
    aria-label="Main navigation in small size"
  >
    <NavBar.Item id="dashboard">{'Dashboard'}</NavBar.Item>
    <NavBar.Item id="portfolio">{'Portfolio'}</NavBar.Item>
    <NavBar.Item id="market">{'Market'}</NavBar.Item>
    <NavBar.Item id="capacity">{'Capacity'}</NavBar.Item>
    <NavBar.Item id="trade-results">{'Trade results'}</NavBar.Item>
  </NavBar.Root>
</Flex>
```

### Controlled state

By default `NavBar` works in an uncontrolled way, managing its own state internally. Use `defaultActiveItem` prop to set the initial active item.

If you need to control the active item state, you should pass your own state to `activeItem` prop. `onActiveItemChange` handler is called when the active item changes, allowing you to sync state.

```jsx resizable=true
() => {
  const [activePage, setActivePage] = React.useState('home');

  return (
    <NavBar.Root
      activeItem={activePage}
      onActiveItemChange={setActivePage}
      aria-label="Main navigation"
    >
      <NavBar.Item id="home">{'Home'}</NavBar.Item>
      <NavBar.Item id="bidding">{'Bidding'}</NavBar.Item>
      <NavBar.Item id="trade-results">{'Trade results'}</NavBar.Item>
      <NavBar.Item id="insights">{'Insights'}</NavBar.Item>
    </NavBar.Root>
  );
};
```

### Decorators

Use `startElement` and `endElement` props to add custom elements to the start and end of the `NavBar.Item`.

These are useful for providing an [Icon](/components/svg-icon) that visually represents and supports the item or adding a [Label](/components/label) to the item.

<Callout variant="tip">

When item's text is not a direct children of `NavBar.Item`, you should wrap it with `NavBar.ItemLabel`. It is responsible for rendering a visibly hidden "copy" of the item text in bold, reserving box space for when text becomes bold in active state.

</Callout>

```jsx resizable=true
<NavBar.Root
  aria-label="Main navigation with decorators"
  defaultActiveItem="home"
  moreMenuLabel="More pages"
>
  <NavBar.Item id="home" startElement={<SvgIcon iconName="home" />}>
    {'Home'}
  </NavBar.Item>
  <NavBar.Item id="widgets" startElement={<SvgIcon iconName="grid" />}>
    {'Widgets'}
  </NavBar.Item>
  <NavBar.Item id="map" startElement={<SvgIcon iconName="globe2" />}>
    {'Map'}
  </NavBar.Item>
  <NavBar.Item
    id="inbox"
    startElement={<SvgIcon iconName="inbox" />}
    endElement={
      <Label circular size="small">
        {'3'}
      </Label>
    }
  >
    {'Inbox'}
  </NavBar.Item>
  <NavBar.Item id="settings" startElement={<SvgIcon iconName="settings" />}>
    {'Settings'}
  </NavBar.Item>
  <NavBar.Item
    id="finance_reports"
    startElement={<SvgIcon iconName="trendingUp" />}
  >
    {'Finance reports'}
  </NavBar.Item>
</NavBar.Root>
```

### Disabled items

You can disable an item by passing `isDisabled` prop. Disabled items are not focusable and cannot be activated.

```jsx resizable=true
<NavBar.Root
  defaultActiveItem="dashboard"
  aria-label="Main navigation with disabled items"
>
  <NavBar.Item id="dashboard" startElement={<SvgIcon iconName="layout" />}>
    {'Dashboard'}
  </NavBar.Item>
  <NavBar.Item id="map" startElement={<SvgIcon iconName="globe2" />} isDisabled>
    {'Map'}
  </NavBar.Item>
  <NavBar.Item id="editor" startElement={<SvgIcon iconName="area" />}>
    {'Editor'}
  </NavBar.Item>
  <NavBar.Item
    id="alerts"
    startElement={<SvgIcon iconName="bell" />}
    isDisabled
  >
    {'Alerts'}
  </NavBar.Item>
  <NavBar.Item id="graphs" startElement={<SvgIcon iconName="barChart2" />}>
    {'Graphs'}
  </NavBar.Item>
  <NavBar.Item id="users-management" startElement={<SvgIcon iconName="user" />}>
    {'Users management'}
  </NavBar.Item>
</NavBar.Root>
```

### With app frame

Use `NavBar` with [App Frame component](/components/app-frame) to provide the structure for the application navigation.

`NavBar` should be placed below the application header and directly above the content it affects.

```jsx resizable=true
<AppFrame.Root
  css={{
    // the following override is added only to make the demo
    // display better in the playground
    maxHeight: '60vh'
  }}
  background="neutralModerate"
>
  <AppFrame.AppHeader>
    <AppHeader.Root>
      <AppHeader.Logo
        variant={{
          '@initial': 'icon',
          '@mqLargeAndUp': 'wordmark'
        }}
      />
      <AppHeader.Title>{'Product Name'}</AppHeader.Title>
    </AppHeader.Root>
  </AppFrame.AppHeader>
  <AppFrame.NavBar>
    <NavBar.Root defaultActiveItem="dashboard" aria-label="Main navigation">
      <NavBar.Item id="dashboard" startElement={<SvgIcon iconName="layout" />}>
        {'Dashboard'}
      </NavBar.Item>
      <NavBar.Item id="map" startElement={<SvgIcon iconName="globe2" />}>
        {'Map'}
      </NavBar.Item>
      <NavBar.Item id="editor" startElement={<SvgIcon iconName="area" />}>
        {'Editor'}
      </NavBar.Item>
      <NavBar.Item id="alerts" startElement={<SvgIcon iconName="bell" />}>
        {'Alerts'}
      </NavBar.Item>
      <NavBar.Item id="graphs" startElement={<SvgIcon iconName="barChart2" />}>
        {'Graphs'}
      </NavBar.Item>
      <NavBar.Item
        id="users-management"
        startElement={<SvgIcon iconName="user" />}
      >
        {'Users management'}
      </NavBar.Item>
    </NavBar.Root>
  </AppFrame.NavBar>
  <AppFrame.Main
    padding="spacingM"
    css={{
      display: 'grid',
      placeItems: 'center'
    }}
  >
    <Text color="foregroundNeutralModerate">{'App view'}</Text>
  </AppFrame.Main>
</AppFrame.Root>
```

### With fixed item

You can use `fixedStartItem` or `fixedEndItem` prop to render a fixed item to the left or right side of the nav bar. This item remains visible and accessible at all times, even if the rest of the navigation items overflow.

```jsx resizable=true
<NavBar.Root
  aria-label="Main navigation with fixed item"
  defaultActiveItem="page1"
  fixedEndItem={
    <NavBar.Item
      id="configurationPage"
      startElement={<SvgIcon iconName="settings" />}
    >
      {'Configuration'}
    </NavBar.Item>
  }
>
  <NavBar.Item id="page1" startElement={<SvgIcon iconName="home" />}>
    {'Home'}
  </NavBar.Item>
  <NavBar.Item id="page2" startElement={<SvgIcon iconName="trendingUp" />}>
    {'Reporting'}
  </NavBar.Item>
  <NavBar.Item id="page3" startElement={<SvgIcon iconName="grid" />}>
    {'Widgets'}
  </NavBar.Item>
  <NavBar.Item id="page4" startElement={<SvgIcon iconName="barChart1" />}>
    {'Stats'}
  </NavBar.Item>
</NavBar.Root>
```

### With routing

If you need to use the `Link` component provided by your routing package (e.g. [React Router](https://reactrouter.com/en/main) or [Next.js](https://nextjs.org/docs/api-reference/next/link)), it's recommended to compose it with `NavBar.Item`:

```jsx
import { Link, useLocation } from 'react-router-dom';
import { NavBar } from '@gemini-suite/vera-react';

const routes = [
  {
    to: '/',
    label: 'Home',
    iconName: 'home'
  },
  {
    to: '/dashboard',
    label: 'Dashboard',
    iconName: 'layout'
  },
  {
    to: '/map',
    label: 'Map',
    iconName: 'globe2'
  }
];

function App() {
  const location = useLocation();

  const [activeItem, setActiveItem] = useState(() => location.pathname);

  return (
    <NavBar.Root
      aria-label="Main navigation"
      activeItem={activeItem}
      onActiveItemChange={setActiveItem}
    >
      {routes.map(({ to, label, iconName }) => (
        <NavBar.Item
          key={to}
          id={to}
          as={Link}
          to={to}
          startElement={<SvgIcon iconName={iconName} />}
        >
          {label}
        </NavBar.Item>
      ))}
    </NavBar.Root>
  );
}
```

<Card
  href="https://next--698f15fa99e7b146f9002f64.chromatic.com/?path=/story/components-navbar--with-router"
  title="See complete example in Storybook"
  actionIcon="externalLink"
/>

---

## Accessibility

<ul>
  <li iconName="check">

NavBar is `<nav>` navigation [landmark region](https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/) and can accept the `aria-label` attribute.

  </li>
  <li iconName="check">

The active item is conveyed to assistive technologies using the `aria-current` attribute.

  </li>
  <li iconName="check">

Each item can be reached using the <Kbd>Tab</Kbd> key and activated by using the <Kbd>Enter</Kbd> key.

  </li>
</ul>

---

## API Reference

### Navbar.Root

| Name                 | Type                   | Default    | Description                                                                                                                                                                                                                                  | Required |
| -------------------- | ---------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`                | `StitchesCss`          |            | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |
| `defaultActiveItem`  | `string`               |            | The id of the initial active item when nav bar is first rendered. Use when you do not need to control active item id.                                                                                                                        |          |
| `activeItem`         | `string`               |            | The controlled id of the item that should be active. Use in conjunction with `onActiveItemChange`.                                                                                                                                           |          |
| `onActiveItemChange` | `(id: string) => void` |            | Event handler called when the active item id changes.                                                                                                                                                                                        |          |
| `size`               | `"medium" \| "small"`  | `"medium"` | The size of the nav bar.                                                                                                                                                                                                                     |          |
| `fixedStartItem`     | `React.ReactElement`   |            | Fixed item to be rendered to the left side of thenav bar, before the list of items that can overflow.                                                                                                                                        |          |
| `fixedEndItem`       | `React.ReactElement`   |            | Fixed item to be rendered to right side of the nav bar, after the list of items that can overflow.                                                                                                                                           |          |
| `moreMenuLabel`      | `string`               | `"More"`   | Content of the overflow menu button tooltip.                                                                                                                                                                                                 |          |

### Navbar.Item

| Name           | Type                                                      | Default  | Description                                                                                                                                                                                                                                                                                  | Required |
| -------------- | --------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`           | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `button` | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`          | `StitchesCss`                                             |          | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants.                                                 |          |
| `id`           | `string`                                                  |          | A unique identifier for the item.                                                                                                                                                                                                                                                            | Yes      |
| `isDisabled`   | `boolean`                                                 |          | When `true`, the item will be disabled, preventing the user from interacting with it.                                                                                                                                                                                                        |          |
| `startElement` | `React.ReactElement`                                      |          | `ReactElement` to render to the left of the item's children.                                                                                                                                                                                                                                 |          |
| `endElement`   | `React.ReactElement`                                      |          | `ReactElement` to render to the right of the item's children.                                                                                                                                                                                                                                |          |

### Navbar.ItemLabel

| Name  | Type                                                      | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ----- | --------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`  | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `span`  | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css` | `StitchesCss`                                             |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |
