> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Side Nav - Web

> Side Navs are used to display a list of links to move between pages.

> [!NOTE]
>
> For development, import `SideNav` from
> `@servicetitan/anvil2`. For design, find it in the
> [Anvil2 file](https://www.figma.com/design/xaNQsvRKczoxu7pj0M6QT8/Anvil2-v3?node-id=204-1345).

![](https://mintcdn.com/servicetitan/uz2PQSvO75TRhQ38/images/docs/web/components/shared/overview-of-a-side-nav.png?fit=max\&auto=format\&n=uz2PQSvO75TRhQ38\&q=85\&s=27b02db811499bfd0a371a67db6e855d)

## Anatomy

The Side Nav consists of five primary elements that work together to display a list of links to move between pages.

![Anatomy of a Side
Nav](https://mintcdn.com/servicetitan/usDdQzJfkl6jYYLR/images/docs/web/components/side-nav/design/anatomy-of-a-side-nav.png?fit=max\&auto=format\&n=usDdQzJfkl6jYYLR\&q=85\&s=38257bf447e6a72c682ba383d70bc903)

1. Item
2. Selected item
3. Group section
4. Collapsible parent item
5. Nested item

## Options

The Side Nav supports flat list, grouping, and collapsible configurations to accommodate various navigation scenarios.

### Flat List

sidenav-group-false

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/sidenav-group-false?file=src/App.tsx)

```tsx lines theme={null}
import { SideNav, type SideNavLinkProps } from "@servicetitan/anvil2";
import { useState, type MouseEvent } from "react";

function App() {
  const [active, setActive] = useState("2");
  const handleOnClick = (
    _e: MouseEvent<HTMLAnchorElement>,
    id: SideNavLinkProps["id"],
  ) => {
    setActive(id);
  };

  return (
    <SideNav>
      <SideNav.Link id="1" onClick={handleOnClick} active={active === "1"}>
        Side Nav Item 1
      </SideNav.Link>
      <SideNav.Link id="2" onClick={handleOnClick} active={active === "2"}>
        Side Nav Item 2
      </SideNav.Link>
      <SideNav.Link id="3" onClick={handleOnClick} active={active === "3"}>
        Side Nav Item 3
      </SideNav.Link>
      <SideNav.Link id="4" onClick={handleOnClick} active={active === "4"}>
        Side Nav Item 4
      </SideNav.Link>
      <SideNav.Link id="5" onClick={handleOnClick} active={active === "5"}>
        Side Nav Item 5
      </SideNav.Link>
      <SideNav.Link id="6" onClick={handleOnClick} active={active === "6"}>
        Side Nav Item 6
      </SideNav.Link>
    </SideNav>
  );
}

export default App;
```

### Grouping

sidenav-group

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/sidenav-group?file=src/App.tsx)

```tsx lines theme={null}
import { SideNav, type SideNavLinkProps } from "@servicetitan/anvil2";
import { useState, type MouseEvent } from "react";

function App() {
  const [active, setActive] = useState("2");
  const handleOnClick = (
    _e: MouseEvent<HTMLAnchorElement>,
    id: SideNavLinkProps["id"],
  ) => {
    setActive(id);
  };

  return (
    <SideNav aria-label="Side Nav Title">
      <SideNav.Group label="Group Item 1">
        <SideNav.Link id="1" onClick={handleOnClick} active={active === "1"}>
          Side Nav Item 1
        </SideNav.Link>
        <SideNav.Link id="2" onClick={handleOnClick} active={active === "2"}>
          Side Nav Item 2
        </SideNav.Link>
        <SideNav.Link id="3" onClick={handleOnClick} active={active === "3"}>
          Side Nav Item 3
        </SideNav.Link>
      </SideNav.Group>
      <SideNav.Group label="Group Item 2">
        <SideNav.Link id="4" onClick={handleOnClick} active={active === "4"}>
          Side Nav Item 4
        </SideNav.Link>
        <SideNav.Link id="5" onClick={handleOnClick} active={active === "5"}>
          Side Nav Item 5
        </SideNav.Link>
        <SideNav.Link id="6" onClick={handleOnClick} active={active === "6"}>
          Side Nav Item 6
        </SideNav.Link>
      </SideNav.Group>
    </SideNav>
  );
}

export default App;
```

### Collapsible

Parent items are purely accordions, and are not links themselves.

sidenav-collapsible

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/sidenav-collapsible?file=src/App.tsx)

```tsx lines theme={null}
import { SideNav, type SideNavLinkProps } from "@servicetitan/anvil2";
import { useState, type MouseEvent } from "react";

function App() {
  const [active, setActive] = useState("2");
  const handleOnClick = (
    _e: MouseEvent<HTMLAnchorElement>,
    id: SideNavLinkProps["id"],
  ) => {
    setActive(id);
  };

  return (
    <SideNav aria-label="Side Nav Title">
      <SideNav.Collapsible defaultExpanded label="Parent Item 1">
        <SideNav.Link id="1" onClick={handleOnClick} active={active === "1"}>
          Child Item 1
        </SideNav.Link>
        <SideNav.Link id="2" onClick={handleOnClick} active={active === "2"}>
          Child Item 2
        </SideNav.Link>
        <SideNav.Link id="3" onClick={handleOnClick} active={active === "3"}>
          Child Item 3
        </SideNav.Link>
      </SideNav.Collapsible>

      <SideNav.Collapsible label="Parent Item 2">
        <SideNav.Link id="4" onClick={handleOnClick} active={active === "4"}>
          Child Item 1
        </SideNav.Link>
        <SideNav.Link id="5" onClick={handleOnClick} active={active === "5"}>
          Child Item 2
        </SideNav.Link>
        <SideNav.Link id="6" onClick={handleOnClick} active={active === "6"}>
          Child Item 3
        </SideNav.Link>
      </SideNav.Collapsible>

      <SideNav.Collapsible defaultExpanded label="Parent Item 3">
        <SideNav.Link id="7" onClick={handleOnClick} active={active === "7"}>
          Child Item 1
        </SideNav.Link>
        <SideNav.Link id="8" onClick={handleOnClick} active={active === "8"}>
          Child Item 2
        </SideNav.Link>
        <SideNav.Link id="9" onClick={handleOnClick} active={active === "9"}>
          Child Item 3
        </SideNav.Link>
      </SideNav.Collapsible>
    </SideNav>
  );
}

export default App;
```

## Behavior

The Side Nav responds to user interaction with distinct visual states and text overflow handling.

### Visual States

sidenav-data-interactive

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/sidenav-data-interactive?file=src/App.tsx)

```tsx lines theme={null}
import { SideNav } from "@servicetitan/anvil2";

function App() {
  return (
    <SideNav>
      <SideNav.Link id="1">Rest</SideNav.Link>
      <SideNav.Link id="1" data-interactive="hover">
        Hover
      </SideNav.Link>
      <SideNav.Link id="1" data-interactive="active">
        Active
      </SideNav.Link>
      <SideNav.Link id="1" data-interactive="focus-visible">
        Focus Visible
      </SideNav.Link>
      <SideNav.Link id="1" disabled>
        Disabled
      </SideNav.Link>
    </SideNav>
  );
}

export default App;
```

sidenav-data-interactive-selected

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/sidenav-data-interactive-selected?file=src/App.tsx)

```tsx lines theme={null}
import { SideNav } from "@servicetitan/anvil2";

function App() {
  return (
    <SideNav>
      <SideNav.Link id="1" active>
        Selected Rest
      </SideNav.Link>
      <SideNav.Link id="1" data-interactive="hover" active>
        Selected Hover
      </SideNav.Link>
      <SideNav.Link id="1" data-interactive="active" active>
        Selected Active
      </SideNav.Link>
      <SideNav.Link id="1" data-interactive="focus-visible" active>
        Selected Focus Visible
      </SideNav.Link>
      <SideNav.Link id="1" disabled active>
        Selected Disabled
      </SideNav.Link>
    </SideNav>
  );
}

export default App;
```

### Text Overflow

Each item in the Side Nav will wrap when not enough space is available.

sidenav-group-overflow

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/sidenav-group-overflow?file=src/App.tsx)

```tsx lines theme={null}
import { SideNav, type SideNavLinkProps } from "@servicetitan/anvil2";
import { useState, type MouseEvent } from "react";

function App() {
  const [active, setActive] = useState("2");
  const handleOnClick = (
    _e: MouseEvent<HTMLAnchorElement>,
    id: SideNavLinkProps["id"],
  ) => {
    setActive(id);
  };

  return (
    <SideNav style={{ maxWidth: "200px" }} aria-label="Side Nav Title">
      <SideNav.Group label="Group item that will wrap when not enough space is available">
        <SideNav.Collapsible
          defaultExpanded
          label="Parent item that will wrap when not enough space is available"
        >
          <SideNav.Link id="7" onClick={handleOnClick} active={active === "1"}>
            Child Item 1
          </SideNav.Link>
          <SideNav.Link id="8" onClick={handleOnClick} active={active === "2"}>
            Child item that will wrap when not enough space is available
          </SideNav.Link>
          <SideNav.Link id="9" onClick={handleOnClick} active={active === "3"}>
            Child Item 3
          </SideNav.Link>
        </SideNav.Collapsible>
      </SideNav.Group>
    </SideNav>
  );
}

export default App;
```

## Usage Guidelines

| Standard | Requirement |
| - | - |
| DoDisplay links for moving between pages | Use the Side Nav to display a list of links for moving between pages. |
| DoMatch the app's navigation structure | Use the Side Nav based on how the larger app organizes its navigation structure. In some cases this means the Side Nav is the top-level navigation tool, in others it may be a secondary system. |
| DoUse collapsible when hierarchy is clear | Use a collapsible Side Nav when users understand the categorization, helping them find items more effectively. Avoid this structure if there's no clear parent-child relation in the nav, especially if users cannot perceive it. |
| DoUse flat for fewer or semi-related items | Use a flat Side Nav when items in a group lack a clear hierarchy. A flattened Side Nav is easier for users to navigate in this situation. |
| DoPair subheaders and collapsible in complex navs | Navigations with nuanced levels of hierarchy can use both subheaders and nesting at once. Simpler navigations should consider using only one grouping method. |
| DoShow metadata with Chips | A [Chip](https://anvil.servicetitan.com/docs/components/chip/web.md) can be paired with the Side Nav to provide metadata such as beta or new status, or a numerical value related to the Side Nav item. |
| Don'tMake a parent item a link | The Side Nav's parent item can never be a link. If a parent item link is needed, a child item at the top may be used in its place, e.g., Overview. |
| Don'tUse multi-nested Navs | The Side Nav does not support deep navigation. Simplify the navigation structure first. If it cannot be simplified, a custom solution is needed. |
| Don'tAdd secondary actions | The Side Nav does not support secondary actions for accessibility reasons. Consider placing these actions elsewhere, such as on the page the Side Nav item goes to. |

### Alternatives

#### Side Nav vs Tabs

Side Navs and [Tabs](https://anvil.servicetitan.com/docs/components/tab/web.md) perform similar tasks of organizing content. In most situations, Side Navs are a higher level of the navigation structure compared to Tabs, and are also able to organize less related items together compared to Tabs.

## Content

Content within the Side Nav should clearly communicate navigation destinations through descriptive labels.

## Keyboard Interaction

Users can navigate the Side Nav using standard keyboard controls.

| Key | Interaction |
| - | - |
| Down Arrow | Moves focus to next item |
| Up Arrow | Moves focus to previous item |
| Enter or Space | Selects item, expands/collapses. Focus stays on that item. |

## Code

**Implementation**

sidenav-playground

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/sidenav-playground?file=src/App.tsx)

```tsx lines expandable theme={null}
import { SideNav } from "@servicetitan/anvil2";

function App() {
  return (
    <SideNav aria-label="Page Name">
      <SideNav.Link id="home">Home</SideNav.Link>
      <SideNav.Link id="dashboard">Dashboard</SideNav.Link>
      <SideNav.Group label="Reports">
        <SideNav.Link id="reports-all">All</SideNav.Link>
        <SideNav.Link id="reports-custom">Custom</SideNav.Link>
      </SideNav.Group>
      <SideNav.Collapsible label="Settings">
        <SideNav.Link id="settings-global">Global Settings</SideNav.Link>
        <SideNav.Link id="settings-user" active>
          User Preferences
        </SideNav.Link>
      </SideNav.Collapsible>
    </SideNav>
  );
}

export default App;
```

## Common Examples

```tsx theme={null}
import { SideNav } from "@servicetitan/anvil2";

function ExampleComponent() {
  return (
    <SideNav>
      <SideNav.Item id="item-1">Item 1</SideNav.Item>
      <SideNav.Item id="item-2">Item 2</SideNav.Item>
    </SideNav>
  );
}
```

### Grouping side nav items

Side nav items can be grouped in two different ways, using `SideNav.Group` or `SideNav.Collapsible`.

sidenav-group

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/sidenav-group?file=src/App.tsx)

```tsx lines expandable theme={null}
import { SideNav, type SideNavLinkProps } from "@servicetitan/anvil2";
import { useState, type MouseEvent } from "react";

function App() {
  const [active, setActive] = useState("2");
  const handleOnClick = (
    _e: MouseEvent<HTMLAnchorElement>,
    id: SideNavLinkProps["id"],
  ) => {
    setActive(id);
  };

  return (
    <SideNav aria-label="Side Nav Title">
      <SideNav.Group label="Group Item 1">
        <SideNav.Link id="1" onClick={handleOnClick} active={active === "1"}>
          Side Nav Item 1
        </SideNav.Link>
        <SideNav.Link id="2" onClick={handleOnClick} active={active === "2"}>
          Side Nav Item 2
        </SideNav.Link>
        <SideNav.Link id="3" onClick={handleOnClick} active={active === "3"}>
          Side Nav Item 3
        </SideNav.Link>
      </SideNav.Group>
      <SideNav.Group label="Group Item 2">
        <SideNav.Link id="4" onClick={handleOnClick} active={active === "4"}>
          Side Nav Item 4
        </SideNav.Link>
        <SideNav.Link id="5" onClick={handleOnClick} active={active === "5"}>
          Side Nav Item 5
        </SideNav.Link>
        <SideNav.Link id="6" onClick={handleOnClick} active={active === "6"}>
          Side Nav Item 6
        </SideNav.Link>
      </SideNav.Group>
    </SideNav>
  );
}

export default App;
```

#### Using SideNav.Group

Use the `SideNav.Group` component to group multiple links.

sidenav-collapsible

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/sidenav-collapsible?file=src/App.tsx)

```tsx lines expandable theme={null}
import { SideNav, type SideNavLinkProps } from "@servicetitan/anvil2";
import { useState, type MouseEvent } from "react";

function App() {
  const [active, setActive] = useState("2");
  const handleOnClick = (
    _e: MouseEvent<HTMLAnchorElement>,
    id: SideNavLinkProps["id"],
  ) => {
    setActive(id);
  };

  return (
    <SideNav aria-label="Side Nav Title">
      <SideNav.Collapsible defaultExpanded label="Parent Item 1">
        <SideNav.Link id="1" onClick={handleOnClick} active={active === "1"}>
          Child Item 1
        </SideNav.Link>
        <SideNav.Link id="2" onClick={handleOnClick} active={active === "2"}>
          Child Item 2
        </SideNav.Link>
        <SideNav.Link id="3" onClick={handleOnClick} active={active === "3"}>
          Child Item 3
        </SideNav.Link>
      </SideNav.Collapsible>

      <SideNav.Collapsible label="Parent Item 2">
        <SideNav.Link id="4" onClick={handleOnClick} active={active === "4"}>
          Child Item 1
        </SideNav.Link>
        <SideNav.Link id="5" onClick={handleOnClick} active={active === "5"}>
          Child Item 2
        </SideNav.Link>
        <SideNav.Link id="6" onClick={handleOnClick} active={active === "6"}>
          Child Item 3
        </SideNav.Link>
      </SideNav.Collapsible>

      <SideNav.Collapsible defaultExpanded label="Parent Item 3">
        <SideNav.Link id="7" onClick={handleOnClick} active={active === "7"}>
          Child Item 1
        </SideNav.Link>
        <SideNav.Link id="8" onClick={handleOnClick} active={active === "8"}>
          Child Item 2
        </SideNav.Link>
        <SideNav.Link id="9" onClick={handleOnClick} active={active === "9"}>
          Child Item 3
        </SideNav.Link>
      </SideNav.Collapsible>
    </SideNav>
  );
}

export default App;
```

#### Using SideNav.Collapsible

To make groups of items collapsible, use the `SideNav.Collapsible` component.

### Routing with Side Nav Links

As of version `1.16.9`, the `pathname` prop of the `SideNav.Link` component enables native browser routing using the `history.pushState()` function. This is essentially what `react-router-dom` does, and this method prevents extra dependencies in the `@servicetitan/anvil2` package.

```tsx theme={null}
<SideNav.Link pathname="/example/path">Example Path</SideNav.Link>
```

## React Accessibility

### Multiple Navigation Landmark

When there is more than one navigation landmark on a page, each should have a unique label. For example, if a `SideNav` exists on the same page as another navigational element, such as an app bar using a `nav` element, they should both have unique labels.

Reference: [W3 Navigation Landmark](https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/examples/navigation.html)

sidenav-multiplenavigationlandmark

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/sidenav-multiplenavigationlandmark?file=src/App.tsx)

```tsx lines expandable theme={null}
import { SideNav, Flex, Text } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex direction="column">
      <Text el="h2" variant="headline" id="first-nav">
        First Navigation Landmark
      </Text>
      <SideNav aria-labelledby="first-nav">
        <SideNav.Link id="first-01">Item 1-1</SideNav.Link>
        <SideNav.Link id="first-02">Item 1-2</SideNav.Link>
      </SideNav>
      <Text el="h2" variant="headline" id="second-nav">
        Second Navigation Landmark
      </Text>
      <SideNav aria-labelledby="second-nav">
        <SideNav.Link id="second-01">Item 2-1</SideNav.Link>
        <SideNav.Link id="second-02">Item 2-2</SideNav.Link>
      </SideNav>
    </Flex>
  );
}

export default App;
```

For more guidance on semantic page structure and navigation landmarks, see [semantic markup best practices](https://anvil.servicetitan.com/docs/accessibility/semantic-markup.md#sections-articles-and-asides).

**SideNav Props**

```tsx theme={null}
import { SideNav } from "@servicetitan/anvil2";

function ExampleComponent() {
return <SideNav aria-label="Main navigation">...</SideNav>;
}

```

## `SideNav` Props

The `SideNav` component can accept any valid HTML `nav` element props.

**SideNav.Link Props**

```tsx theme={null}
import { SideNav } from "@servicetitan/anvil2";

function ExampleComponent() {
  return (
    <SideNav.Link
      id="link-1"
      pathname="/example"
      active={false}
      exact={false}
    >
      Link Text
    </SideNav.Link>
  );
}
```

## `SideNav.Link` Props

The `SideNav.Link` component can accept any valid HTML `a` props, as well as the following:

**id** `string` *required*

Unique identifier for the navigation link. Required to enable keyboard navigation.

**active** `boolean`

When true, marks the link as the current active page.

**disabled** `boolean`

When true, disables the link and prevents interaction.

**pathname** `string`

Pathname for client-side routing. Using this will trigger History API navigation.

**search** `string`

Optional search parameters for the URL. Can only be used if `pathname` has a value.

**SideNav.Group Props**

```tsx theme={null}
import { SideNav } from "@servicetitan/anvil2";

function ExampleComponent() {
return (

<SideNav.Group label="Group Label">
  <SideNav.Link id="link-1">Link 1</SideNav.Link>
</SideNav.Group>
); }

```

## `SideNav.Group` Props

The `SideNav.Group` component can accept any valid HTML `li` props, as well as the following:

**label** `string` *required*

The label text displayed for the navigation group.

**SideNav.Collapsible Props**

```tsx theme={null}
import { SideNav } from "@servicetitan/anvil2";

function ExampleComponent() {
  return (
    <SideNav.Collapsible label="Collapsible Group" defaultExpanded={false}>
      <SideNav.Link id="link-1">Link 1</SideNav.Link>
    </SideNav.Collapsible>
  );
}
```

## `SideNav.Collapsible` Props

The `SideNav.Collapsible` component can accept any valid HTML `li` props, as well as the following:

**label** `string` *required*

The label text displayed for the collapsible section.

**defaultExpanded** `boolean` (default: false)

Initial expansion state for uncontrolled usage.

**expanded** `boolean`

Controlled expansion state.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.