# Mobile Nav

## Usage

`MobileNav` is a dialog drawer that slides in from one side of the screen, not a bottom sheet. Bind `MobileNavToggle` to the same `v-model:is-open`. While open, focus stays in the drawer. Escape or a press on the scrim closes it and returns focus to where it was. If another layer opens inside the drawer, Escape closes that top layer first. Pinch-zoom stays with the browser, and the body can still scroll vertically.

`side` is `start`, `end`, or `auto`. `auto` picks the side from where focus was when the drawer opened. The top nav creates this pair for you when its media query matches.

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

const open = ref(false)
</script>

<template>
  <MobileNavToggle v-model:is-open="open" controls="app-nav" />
  <MobileNav id="app-nav" v-model:is-open="open" header="Menu" side="start">
    <!-- items -->
  </MobileNav>
</template>
```

### Anatomy

- **Navigation overlay**: Full-viewport dialog overlay that hosts the mobile navigation drawer.
- **Drawer**: Painted panel that slides in from the resolved viewport edge.
- **Header**: Fixed row containing optional header content and the close button.
- **Content**: Scrollable region containing the navigation content.
- **Close button**: Button that closes the navigation drawer.
- **Toggle button**: AppShell-aware Button that opens or closes the drawer on mobile viewports.

## Best practices

| Guidance | Practice |
| --- | --- |
| Do | Point the toggle `controls` at the drawer id so the button and dialog are related. |
| Do | Put ordinary links in the drawer. Do not wrap them in another <code>role="menu"</code>. |
| Avoid | Do not use a bottom sheet for this navigation. It is a side drawer. |

## Examples

### Basic Drawer

A menu button opens sectioned navigation.

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

const open = ref(false)
</script>

<template>
  <div>
    <MobileNavToggle v-model:is-open="open" controls="docs-mobile-nav" label="Open Navigation" />
    <MobileNav id="docs-mobile-nav" v-model:is-open="open" header="Navigation" side="start">
      <SideNavSection title="Main">
        <SideNavItem href="#dashboard" icon-class="i-carbon-home" is-selected label="Dashboard" />
        <SideNavItem href="#projects" icon-class="i-carbon-folder" label="Projects" />
        <SideNavItem href="#analytics" icon-class="i-carbon-analytics" label="Analytics" />
      </SideNavSection>
      <SideNavSection title="Settings">
        <SideNavItem href="#settings" icon-class="i-carbon-settings" label="General" />
        <SideNavItem href="#team" icon-class="i-carbon-group" label="Team" />
      </SideNavSection>
    </MobileNav>
  </div>
</template>
```

### End Side Drawer

The same drawer slides in from the end edge.

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

const open = ref(false)
</script>

<template>
  <div>
    <Button label="Open from Right" @click="open = true" />
    <MobileNav id="docs-mobile-nav-end" v-model:is-open="open" header="Settings" side="end">
      <SideNavSection title="Settings">
        <SideNavItem href="#settings" icon-class="i-carbon-settings" label="General" />
        <SideNavItem href="#team" icon-class="i-carbon-group" label="Team" />
      </SideNavSection>
    </MobileNav>
  </div>
</template>
```

### Without Title

Without a title, the drawer keeps the items and the close button.

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

const open = ref(false)
</script>

<template>
  <div>
    <MobileNavToggle v-model:is-open="open" controls="docs-mobile-nav-plain" label="Open Navigation" />
    <MobileNav id="docs-mobile-nav-plain" v-model:is-open="open" side="start">
      <SideNavSection title="Main">
        <SideNavItem href="#dashboard" icon-class="i-carbon-home" is-selected label="Dashboard" />
        <SideNavItem href="#projects" icon-class="i-carbon-folder" label="Projects" />
      </SideNavSection>
    </MobileNav>
  </div>
</template>
```

## MobileNav Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `isOpen` | `boolean` | `false` | Open state for `v-model:is-open`. |
| `header` | `string` | - | Drawer title. The `header` slot can replace it. |
| `width` | `number` | `320` | Drawer width in pixels. |
| `side` | `'start' \| 'end' \| 'auto'` | `'auto'` | Which edge the drawer enters from. |
| `label` | `string` | The title, or localized “Navigation” | Accessible name when there is no title. |

## MobileNav events

| Name | Description |
| --- | --- |
| `update:isOpen` | Open state change for `v-model:is-open`. |
| `openChange` | Fired whenever the open state changes. |

## MobileNavToggle Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `isOpen` | `boolean` | `false` | Shares `v-model:is-open` with the drawer. |
| `label` | `string` | “Close” while open, otherwise “Open menu” | Accessible name of the button. |
| `controls` | `string` | - | Drawer id written to `aria-controls`. |
