# useAppShellMobile

## Usage

Hook for reading and controlling AppShell mobile navigation state from descendants of AppShell. Use it for custom mobile nav triggers, closing the drawer after route changes, or coordinating AppShell-adjacent mobile experiences with the same breakpoint used by mobile nav.

```ts
import { useAppShellMobile } from '@astryx-vue/core'
```

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

const { isMobile, isMobileNavEnabled, mobileNavId, openMobileNav } = useAppShellMobile()
</script>

<template>
  <button
    v-if="isMobile && isMobileNavEnabled"
    type="button"
    :aria-controls="mobileNavId"
    @click="openMobileNav"
  >
    Open navigation
  </button>
</template>
```

## Best practices

| Guidance | Practices |
| --- | --- |
| Do | Use inside the AppShell tree when building custom mobile navigation controls, route-aware nav items, or UI that should update at the same breakpoint as AppShell mobile nav. |
| Do | Prefer `MobileNavToggle` for the standard hamburger trigger: use this hook when you need custom placement, styling, or extra behavior. |
| Do | Call `closeMobileNav` after a custom mobile nav item changes route so the drawer dismisses cleanly. |
| Don't | Use as a general responsive primitive when the UI is not inside AppShell or does not need to align with AppShell mobile nav: use `useMediaQuery` instead. |
| Don't | Assume it throws outside AppShell. The hook returns safe defaults and no-op callbacks when no provider is present. |

## Examples

Common configurations, variations, and states.

### useAppShellMobile — Custom Mobile Trigger

Custom mobile navigation trigger built with useAppShellMobile. The trigger consumes the surrounding AppShell context instead of rendering its own shell.

```vue
<script setup lang="ts">
import { useAppShellMobile } from '@astryx-vue/core'
import { Button } from '@astryx-vue/core/Button'
import { HStack, VStack } from '@astryx-vue/core/Stack'
import { Text } from '@astryx-vue/core/Text'

const {
  closeMobileNav,
  isMobile,
  isMobileNavEnabled,
  isMobileNavOpen,
  openMobileNav,
} = useAppShellMobile()
</script>

<template>
  <VStack v-if="!isMobileNavEnabled" :gap="2">
    <Button is-disabled label="Open navigation" variant="secondary" />
    <Text color="secondary" type="body">
      No active AppShell mobile navigation context was detected. This hook returns safe defaults outside AppShell, or when the surrounding AppShell has mobile navigation disabled.
    </Text>
  </VStack>
  <VStack v-else-if="!isMobile" :gap="2">
    <Button is-disabled label="Open navigation" variant="secondary" />
    <Text color="secondary" type="body">
      AppShell mobile navigation context is available. Narrow the viewport below the AppShell mobile breakpoint to make the custom trigger active.
    </Text>
  </VStack>
  <VStack v-else :gap="2">
    <HStack :gap="2" align="center">
      <Button
        :label="isMobileNavOpen ? 'Close navigation' : 'Open navigation'"
        variant="secondary"
        @click="isMobileNavOpen ? closeMobileNav() : openMobileNav()"
      />
      <Text color="secondary" type="body">
        {{ isMobileNavOpen ? 'Mobile nav is open' : 'Mobile nav is closed' }}
      </Text>
    </HStack>
    <Text color="secondary" type="body">
      This button controls the nearest AppShell mobile nav from context.
    </Text>
  </VStack>
</template>
```

## Returns

| Name | Type | Description |
| --- | --- | --- |
| `isMobile` | `boolean` | Whether the current viewport is below the AppShell mobile navigation breakpoint. Use this to synchronize AppShell-adjacent mobile UI with the same breakpoint as mobile nav. |
| `isMobileNavOpen` | `boolean` | Whether the AppShell-managed mobile navigation drawer is open. |
| `mobileNavId` | `string \| undefined` | DOM id of the mobile navigation drawer, set by AppShell. Point `aria-controls` of a custom toggle at this so screen-reader users know which element the toggle expands. Undefined outside an AppShell that manages the drawer. |
| `toggleMobileNav` | `() => void` | Toggle the AppShell-managed mobile navigation drawer. No-ops when mobile nav is disabled. |
| `openMobileNav` | `() => void` | Open the AppShell-managed mobile navigation drawer. No-ops when mobile nav is disabled. |
| `closeMobileNav` | `() => void` | Close the AppShell-managed mobile navigation drawer. |
| `isMobileNavEnabled` | `boolean` | Whether AppShell mobile navigation is enabled and managed by AppShell. False when `mobileNav` is `false`, there is no nav content, or a fully custom `mobileNav` slot owns the drawer. |
| `hasAutoToggle` | `boolean` | Whether AppShell auto-toggle behavior is enabled. False when `mobileNav.hasToggle` is set to `false`; combine with `isMobile` and `isMobileNavEnabled` before rendering custom toggles. |
| `hasSideNav` | `boolean` | Whether the AppShell has a `sideNav` slot. Mobile navigation is only managed when there is nav content to show. |

The returned object is stable and reactive. Read the fields in a template or a computed and they follow the AppShell as the viewport changes.
