# Side Nav

## Usage

`SideNav` is the navigation landmark along one side of a page. Compose it with `SideNavSection`, `SideNavHeading`, and `SideNavItem`. With `collapsible`, the bar can shrink to an icon rail. `SideNavCollapseButton` sits at the top end of the sidebar. Items without an icon are omitted while collapsed. Items with children open in a side menu. The `actions` slot on `SideNavItem` sits beside the primary control, outside the link, and is not rendered while the rail is collapsed.

Control it with `v-model:is-collapsed`. Pass an object to `collapsible` to hide the built-in button or to set a hotkey such as `mod+\\`. With `resizable`, the trailing edge can be dragged. The width starts at 260px and stays between 180px and 480px. The handle hides while the bar is collapsed. Dragging below 160px collapses the bar when collapse is also enabled.

```vue
<script setup lang="ts">
import { SideNav, SideNavItem, SideNavSection } from '@astryx-vue/core/SideNav'
import { ref } from 'vue'

const collapsed = ref(false)
</script>

<template>
  <SideNav v-model:is-collapsed="collapsed" collapsible>
    <SideNavSection title="Workspace">
      <SideNavItem href="/home" icon-class="i-carbon-home" label="Home" />
    </SideNavSection>
  </SideNav>
</template>
```

### Anatomy

- **Product icon and name**: Branding area at the top of the nav.
- **Navigation items**: Sections and groups of navigable links.
- **Collapse/expand toggle**: Toggle to collapse or expand the side nav.

## Best practices

| Guidance | Practice |
| --- | --- |
| Do | Give every collapsible item an icon, or it disappears in the rail. |
| Do | Set `href` when a row both navigates and has children. The label navigates; the chevron collapses. |
| Do | Turn on `resizable` when people should drag the width. Keep collapse on `v-model:is-collapsed` instead of setting it on both `collapsible` and `resizable`. |

## Examples

### End content

Rows end with a menu, a count, a badge, and supporting text.

```vue
<script setup lang="ts">
import { Badge } from '@astryx-vue/core/Badge'
import { MoreMenu } from '@astryx-vue/core/MoreMenu'
import { SideNav, SideNavHeading, SideNavItem, SideNavSection } from '@astryx-vue/core/SideNav'
import { Text } from '@astryx-vue/core/Text'
</script>

<template>
  <div class="side-nav-preview">
    <SideNav>
      <template #header>
        <SideNavHeading heading="My App" heading-href="#home" />
      </template>
      <SideNavSection title="Navigation" is-header-hidden>
        <SideNavItem href="#dashboard" icon-class="i-carbon-home" is-selected label="Dashboard">
          <template #end>
            <MoreMenu
              label="Dashboard actions"
              size="sm"
              :items="[{ label: 'Pin to top' }, { label: 'Rename' }]"
            />
          </template>
        </SideNavItem>
        <SideNavItem href="#projects" icon-class="i-carbon-folder" label="Projects">
          <template #end>
            <Badge>12</Badge>
          </template>
        </SideNavItem>
        <SideNavItem href="#analytics" icon-class="i-carbon-analytics" label="Analytics">
          <template #end>
            <Badge>New</Badge>
          </template>
        </SideNavItem>
        <SideNavItem href="#team" icon-class="i-carbon-group" label="Team">
          <template #end>
            <Text color="secondary" type="supporting">
              8 members
            </Text>
          </template>
        </SideNavItem>
      </SideNavSection>
    </SideNav>
  </div>
</template>
```

### Nested items

Settings opens a collapsible group of children.

```vue
<script setup lang="ts">
import { SideNav, SideNavHeading, SideNavItem, SideNavSection } from '@astryx-vue/core/SideNav'
</script>

<template>
  <div class="side-nav-preview">
    <SideNav>
      <template #header>
        <SideNavHeading heading="My App" />
      </template>
      <SideNavSection title="Main">
        <SideNavItem href="#dashboard" icon-class="i-carbon-home" is-selected label="Dashboard" />
        <SideNavItem icon-class="i-carbon-settings" label="Settings">
          <SideNavItem href="#settings-general" label="General" />
          <SideNavItem href="#settings-security" label="Security" />
          <SideNavItem href="#settings-notifications" label="Notifications" />
        </SideNavItem>
      </SideNavSection>
    </SideNav>
  </div>
</template>
```

### Header with menu

The heading is an account switcher, with the product name and the current account.

```vue
<script setup lang="ts">
import { NavIcon } from '@astryx-vue/core/NavItem'
import { NavHeadingMenu, NavHeadingMenuItem } from '@astryx-vue/core/NavMenu'
import { SideNav, SideNavHeading, SideNavItem, SideNavSection } from '@astryx-vue/core/SideNav'
</script>

<template>
  <div class="side-nav-preview">
    <SideNav>
      <template #header>
        <SideNavHeading heading="Product Name" subheading="Business Account">
          <template #icon>
            <NavIcon icon-class="i-carbon-cube" label="Product" />
          </template>
          <template #menu>
            <NavHeadingMenu label="Accounts">
              <NavHeadingMenuItem href="#personal" label="Personal Account" />
              <NavHeadingMenuItem href="#acme" label="Acme Corp" />
              <NavHeadingMenuItem href="#add" label="Add account" />
              <NavHeadingMenuItem href="#sign-out" label="Sign out" />
            </NavHeadingMenu>
          </template>
        </SideNavHeading>
      </template>
      <SideNavSection title="Navigation">
        <SideNavItem href="#dashboard" icon-class="i-carbon-home" is-selected label="Dashboard" />
        <SideNavItem href="#settings" icon-class="i-carbon-settings" label="Settings" />
      </SideNavSection>
    </SideNav>
  </div>
</template>
```

### Resizable width

Drag the handle on the trailing edge to change the width. Dragging it narrow collapses the bar and hides the handle.

```vue
<script setup lang="ts">
import { SideNav, SideNavItem, SideNavSection } from '@astryx-vue/core/SideNav'
</script>

<template>
  <div class="side-nav-preview" style="width: min(100%, 32rem); height: 280px">
    <SideNav collapsible resizable>
      <SideNavSection title="Library">
        <SideNavItem href="#home" icon-class="i-carbon-home" is-selected label="Home" />
        <SideNavItem href="#files" icon-class="i-carbon-folder" label="Files" />
        <SideNavItem href="#mail" icon-class="i-carbon-email" label="Mail" />
      </SideNavSection>
    </SideNav>
  </div>
</template>
```

## SideNav Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | Localized “Sidebar” | Accessible name of the navigation landmark. |
| `collapsible` | `boolean \| SideNavCollapsible` | `false` | Allows the icon rail. An object can set the initial state, the built-in button, and a hotkey. |
| `isCollapsed` | `boolean` | - | Controlled collapsed state for `v-model:is-collapsed`. |
| `resizable` | `boolean \| SideNavResizable` | `false` | Drag the trailing edge. An object can set the starting, minimum, and maximum widths, and an `autoSaveId` that remembers the width. |
| `handleRef` | `HandleRef` | - | A button outside the bar can collapse, expand, and toggle. Sharing `v-model:is-collapsed` is the usual approach. |

## SideNav events

| Name | Description |
| --- | --- |
| `update:isCollapsed` | Collapsed state change for `v-model:is-collapsed`. |
| `collapsedChange` | Fired whenever the collapsed state changes. |
| `widthChange` | Fired while dragging, with the width in pixels. |

## SideNav slots

| Name | Description |
| --- | --- |
| `default` | Main navigation, usually sections and items. |
| `header` | Brand block at the top. |
| `top` | Extra content under the brand block. |
| `footer` | Footer content, above the collapse button. |
| `footerIcons` | Icons on the same row as the collapse button. |

## SideNavSection Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `string` | - | Group title. Stays available to assistive tech when collapsed. |
| `subtitle` | `string` | - | Supporting line under the title. |
| `isHeaderHidden` | `boolean` | `false` | Hides the title visually. |

## SideNavItem Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | - | Item name. |
| `href` | `string` | - | Destination. With children, the label navigates and the chevron collapses. |
| `as` | `NavLinkComponent` | `'a'` | Link root. |
| `iconClass` | `string` | - | CSS icon class. Items without an icon are omitted while collapsed. |
| `isSelected` | `boolean` | `false` | Current page. |
| `isDisabled` | `boolean` | `false` | Disables the item. |
| `collapsible` | `boolean \| object` | - | Whether children can collapse. `false` keeps them open. |

## SideNavItem slots

| Name | Description |
| --- | --- |
| `default` | Child items. |
| `icon` | Icon before the label. |
| `selectedIcon` | Icon shown while the item is selected. |
| `end` | Content at the end of the primary control, still inside the link or button. |
| `actions` | Controls beside the primary control, such as an icon button. They stay outside the link and are omitted while the rail is collapsed. |

## SideNavHeading Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `heading` | `string` | - | Product or app name. |
| `headingHref` | `string` | - | Link for the main title. |
| `superheading` | `string` | - | Small line above the title. |
| `superheadingHref` | `string` | - | Link for the line above the title. |
| `subheading` | `string` | - | Small line below the title. |
| `subheadingHref` | `string` | - | Link for the line below the title. |
| `logoLabel` | `string` | - | Accessible name when the logo is a link on its own. Falls back to `heading`. |
| `as` | `NavLinkComponent` | `'a'` | Link root. |

## SideNavHeading slots

| Name | Description |
| --- | --- |
| `icon` | Mark in front of the title. This is all that remains while collapsed. |
| `end` | Trailing content on the title row. |
| `menu` | Popup menu, usually a `NavHeadingMenu`. The scope provides `close` and `focusRequest`. |

## SideNavCollapseButton Props

Toggles the rail between its expanded and collapsed states. Inside a `SideNav` it reads the collapse state from the sidebar; outside one, bind it with `v-model:is-collapsed`.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | - | Button text. With a label the button renders the chevron plus the text; without one it is icon only and the translated “Collapse sidebar” / “Expand sidebar” becomes its accessible name. |
| `collapsible` | `SideNavControlledCollapsible` | - | Controlled `{ isCollapsed, onCollapsedChange }` config, for buttons rendered outside the sidebar. Pass the same object to `SideNav`. It wins over `isCollapsed`. |
| `isCollapsed` | `boolean` | - | Controlled collapsed state for `v-model:is-collapsed`, for buttons rendered outside the sidebar. |
| `size` | `'sm' \| 'md' \| 'lg'` | Container: `sm` in a SideNav, otherwise `md` | Button size. Set it when the button sits outside a sized container and has to match its neighbours. |

## SideNavCollapseButton slots

| Name | Description |
| --- | --- |
| `default` | Custom content for the button's icon slot. Replaces the chevron; the visible text still comes from `label`. |
