# Top Nav

## Usage

`TopNav` is the navigation landmark across the top of a page. `heading`, `start`, the default slot, and `center` run from the leading edge, and `end` stays at the trailing edge. `TopNavHeading` can show a logo, a line above the title, a line below it, and a menu. `TopNavMenu` opens a menu. `TopNavMegaMenu` opens a larger panel with items and a featured card. The card can show an image, and its action is its own link. Arrow keys move through the items and Escape closes the panel.

Pass `mobileQuery` and, when it matches, the leading and center content moves into `MobileNav`. The bar keeps the heading, the end slot, and the toggle. A slot is not rendered in both places at once.

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

<template>
  <TopNav mobile-query="(max-width: 800px)">
    <template #heading>
      <TopNavHeading heading="Northwind" href="/" />
    </template>
    <TopNavMenu label="Product" :items="[{ label: 'Analytics', href: '/analytics' }]" />
  </TopNav>
</template>
```

### Anatomy

- **Product icon and name**: Identifies the product in the navigation bar.
- **Navigation items**: Primary links for product-level destinations.
- **More menu**: Overflow menu for additional navigation items.
- **Flex area**: Flexible region for search, primary action buttons, or other controls.

## Best practices

| Guidance | Practice |
| --- | --- |
| Do | Give menu items an `href`. ArrowDown opens, arrows move, Escape closes. |
| Do | Use `mobileQuery` on small screens instead of copying the same links into a drawer. |
| Avoid | Do not put a form in the mega menu. It is navigation, not a dialog. |

## Examples

### Centered navigation

Nav items sit in the center. The heading stays at the start, and actions stay at the end.

```vue
<script setup lang="ts">
import { Button } from '@astryx-vue/core/Button'
import { NavIcon } from '@astryx-vue/core/NavItem'
import { TopNav, TopNavHeading, TopNavItem } from '@astryx-vue/core/TopNav'
</script>

<template>
  <div class="nav-frame">
    <TopNav label="Main navigation">
      <template #heading>
        <TopNavHeading heading="My App" href="#home">
          <template #icon>
            <NavIcon icon-class="i-carbon-cube" />
          </template>
        </TopNavHeading>
      </template>
      <template #center>
        <TopNavItem href="#home" is-selected label="Home" />
        <TopNavItem href="#products" label="Products" />
        <TopNavItem href="#about" label="About" />
      </template>
      <template #end>
        <Button is-icon-only label="Search" variant="ghost">
          <template #icon>
            <span class="i-carbon-search" />
          </template>
        </Button>
        <Button is-icon-only label="Profile" variant="ghost">
          <template #icon>
            <span class="i-carbon-user" />
          </template>
        </Button>
      </template>
    </TopNav>
  </div>
</template>
```

### Enterprise dashboard

Icon-labeled items, search, a notification, and a primary action.

```vue
<script setup lang="ts">
import { Button } from '@astryx-vue/core/Button'
import { NavIcon } from '@astryx-vue/core/NavItem'
import { TopNav, TopNavHeading, TopNavItem } from '@astryx-vue/core/TopNav'
</script>

<template>
  <div class="nav-frame">
    <TopNav label="Main navigation">
      <template #heading>
        <TopNavHeading heading="My App" href="#home">
          <template #icon>
            <NavIcon icon-class="i-carbon-cube" />
          </template>
        </TopNavHeading>
      </template>
      <TopNavItem href="#dashboard" icon-class="i-carbon-home" is-selected label="Dashboard" />
      <TopNavItem href="#reports" icon-class="i-carbon-document" label="Reports" />
      <template #end>
        <Button is-icon-only label="Search" variant="ghost">
          <template #icon>
            <span class="i-carbon-search" />
          </template>
        </Button>
        <Button is-icon-only label="Notifications" variant="ghost">
          <template #icon>
            <span class="i-carbon-notification" />
          </template>
        </Button>
        <Button label="Upgrade" variant="primary" />
      </template>
    </TopNav>
  </div>
</template>
```

### Hover menu

Hover opens a product menu with icons and descriptions.

```vue
<script setup lang="ts">
import { Button } from '@astryx-vue/core/Button'
import { NavIcon } from '@astryx-vue/core/NavItem'
import { TopNav, TopNavHeading, TopNavItem, TopNavMenu } from '@astryx-vue/core/TopNav'
</script>

<template>
  <div class="nav-frame">
    <TopNav label="Main navigation">
      <template #heading>
        <TopNavHeading heading="My App" href="#home">
          <template #icon>
            <NavIcon icon-class="i-carbon-cube" />
          </template>
        </TopNavHeading>
      </template>
      <TopNavItem href="#home" is-selected label="Home" />
      <TopNavMenu
        label="Products"
        :items="[
          { description: 'Track and analyze user behavior', href: '#analytics', iconClass: 'i-carbon-analytics', label: 'Analytics' },
          { description: 'Enterprise-grade protection', href: '#security', iconClass: 'i-carbon-security', label: 'Security' },
          { description: 'Streamline your workflows', href: '#automation', iconClass: 'i-carbon-flash', label: 'Automation' },
          { description: 'APIs, SDKs, and CLI tools', href: '#dev-tools', iconClass: 'i-carbon-code', label: 'Developer Tools' },
        ]"
      />
      <TopNavItem href="#pricing" label="Pricing" />
      <template #end>
        <Button is-icon-only label="Profile" variant="ghost">
          <template #icon>
            <span class="i-carbon-user" />
          </template>
        </Button>
      </template>
    </TopNav>
  </div>
</template>
```

### Mega menu

A full-width mega menu with product items. The featured card shows an image, and the action at the bottom is its own link.

```vue
<script setup lang="ts">
import { Button } from '@astryx-vue/core/Button'
import { NavIcon } from '@astryx-vue/core/NavItem'
import { TopNav, TopNavHeading, TopNavItem, TopNavMegaMenu, TopNavMegaMenuFeaturedCard, TopNavMegaMenuItem } from '@astryx-vue/core/TopNav'
</script>

<template>
  <div class="nav-frame">
    <TopNav label="Marketing navigation">
      <template #heading>
        <TopNavHeading heading="My App" href="#home">
          <template #icon>
            <NavIcon icon-class="i-carbon-cube" />
          </template>
        </TopNavHeading>
      </template>
      <TopNavMegaMenu label="Products">
        <TopNavMegaMenuItem description="Track and analyze user behavior across your apps" href="#analytics" icon-class="i-carbon-analytics" title="Analytics" />
        <TopNavMegaMenuItem description="Enterprise-grade protection for your data" href="#security" icon-class="i-carbon-security" title="Security" />
        <TopNavMegaMenuItem description="Streamline workflows with intelligent tools" href="#automation" icon-class="i-carbon-flash" title="Automation" />
        <TopNavMegaMenuItem description="APIs, SDKs, and CLI for integration" href="#dev-tools" icon-class="i-carbon-code" title="Developer Tools" />
        <TopNavMegaMenuItem description="Low-latency edge infra in 40+ regions" href="#network" icon-class="i-carbon-globe" title="Global Network" />
        <template #featured>
          <TopNavMegaMenuFeaturedCard
            description="AI-powered analytics and real-time collaboration."
            image="/template-assets/light-working-horizontal-1.png"
            link-href="#announcement"
            link-label="Read the announcement"
            title="What's new in v4.0"
          />
        </template>
      </TopNavMegaMenu>
      <TopNavItem href="#pricing" label="Pricing" />
      <TopNavItem href="#docs" label="Docs" />
      <template #end>
        <Button label="Sign in" variant="ghost" />
        <Button label="Get started" variant="primary" />
      </template>
    </TopNav>
  </div>
</template>
```

### Heading with menu

The heading shows the suite, the product, and the account. The suite is its own link, and the chevron opens the product menu.

```vue
<script setup lang="ts">
import { NavIcon } from '@astryx-vue/core/NavItem'
import { NavHeadingMenu, NavHeadingMenuItem } from '@astryx-vue/core/NavMenu'
import { TopNav, TopNavHeading, TopNavItem } from '@astryx-vue/core/TopNav'
</script>

<template>
  <div class="nav-frame">
    <TopNav label="Product navigation">
      <template #heading>
        <TopNavHeading
          heading="Console"
          heading-href="#console"
          subheading="Northwind"
          superheading="Acme Suite"
          superheading-href="#suite"
        >
          <template #logo>
            <NavIcon icon-class="i-carbon-cube" />
          </template>
          <template #menu>
            <NavHeadingMenu label="Switch product">
              <NavHeadingMenuItem href="#console" label="Console" />
              <NavHeadingMenuItem description="Usage and reports" href="#analytics" label="Analytics" />
              <NavHeadingMenuItem href="#settings" label="Settings" />
            </NavHeadingMenu>
          </template>
        </TopNavHeading>
      </template>
      <TopNavItem href="#overview" is-selected label="Overview" />
      <TopNavItem href="#docs" label="Docs" />
    </TopNav>
  </div>
</template>
```

### Multiple dropdowns

Several hover menus share one bar and close when the pointer moves to another.

```vue
<script setup lang="ts">
import { NavIcon } from '@astryx-vue/core/NavItem'
import { TopNav, TopNavHeading, TopNavItem, TopNavMenu } from '@astryx-vue/core/TopNav'
</script>

<template>
  <div class="nav-frame">
    <TopNav label="Main navigation">
      <template #heading>
        <TopNavHeading heading="My App" href="#home">
          <template #icon>
            <NavIcon icon-class="i-carbon-cube" />
          </template>
        </TopNavHeading>
      </template>
      <TopNavMenu
        label="Products"
        :items="[
          { description: 'Track behavior', href: '#analytics', iconClass: 'i-carbon-analytics', label: 'Analytics' },
          { description: 'Enterprise protection', href: '#security', iconClass: 'i-carbon-security', label: 'Security' },
        ]"
      />
      <TopNavMenu
        label="Resources"
        :items="[
          { href: '#docs', label: 'Documentation' },
          { href: '#api', label: 'API Reference' },
          { href: '#community', label: 'Community Forum' },
        ]"
      />
      <TopNavItem href="#pricing" label="Pricing" />
    </TopNav>
  </div>
</template>
```

### With logo

A product mark sits in front of the heading, with a profile action at the end.

```vue
<script setup lang="ts">
import { Button } from '@astryx-vue/core/Button'
import { NavIcon } from '@astryx-vue/core/NavItem'
import { TopNav, TopNavHeading, TopNavItem } from '@astryx-vue/core/TopNav'
</script>

<template>
  <div class="nav-frame">
    <TopNav label="Main navigation">
      <template #heading>
        <TopNavHeading heading="My App" href="#home">
          <template #icon>
            <NavIcon icon-class="i-carbon-cube" />
          </template>
        </TopNavHeading>
      </template>
      <TopNavItem href="#overview" is-selected label="Overview" />
      <TopNavItem href="#analytics" label="Analytics" />
      <TopNavItem href="#reports" label="Reports" />
      <template #end>
        <Button is-icon-only label="Profile" variant="ghost">
          <template #icon>
            <span class="i-carbon-user" />
          </template>
        </Button>
      </template>
    </TopNav>
  </div>
</template>
```

## TopNav Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | Localized “Top navigation” | Accessible name of the landmark. |
| `mobileQuery` | `string` | - | When this media query matches, leading and center content moves into the mobile nav. |

## TopNav slots

| Name | Description |
| --- | --- |
| `heading` | Brand title. Stays on the bar at narrow widths. |
| `start` | Content after the title. |
| `default` | Items and menus laid out with `start`. |
| `center` | Centered region. Turns the bar into three columns. |
| `end` | Trailing actions. Stays on the bar at narrow widths. |

## TopNavMenu Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | - | Trigger label. |
| `items` | `TopNavMenuItem[]` | - | Data items. The default slot can render `NavMenuItem` instead. |
| `showDelay` | `number` | `150` | Hover open delay, in milliseconds. |
| `hideDelay` | `number` | `200` | Pointer-leave close delay, in milliseconds. |

## TopNavMegaMenu Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | - | Trigger label and accessible name of the panel. |
| `showDelay` | `number` | `150` | Hover open delay, in milliseconds. |
| `hideDelay` | `number` | `250` | Pointer-leave close delay, in milliseconds. |

Put `TopNavMegaMenuItem` in the default slot and `TopNavMegaMenuFeaturedCard` in `featured`. Inside the drawer the same content becomes an accordion and is not a menu.

## TopNavHeading Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `heading` | `string` | - | Product or app name. Optional when the heading is only a logo. |
| `href` | `string` | - | Link for the main title. Same as `headingHref`, which wins when both are set. |
| `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 and has no readable text beside it. Falls back to `heading`. |
| `as` | `NavLinkComponent` | `'a'` | Link root used when an address is set. It receives `href` and `to`. |

When only the main title has a link and there is no menu, the whole heading is one link. When there is a menu and no links, the whole heading opens the menu. When both are present, each line navigates on its own and only the chevron opens the menu.

## TopNavHeading slots

| Name | Description |
| --- | --- |
| `logo` | Mark in front of the title. Same place as `icon`; `logo` wins. |
| `icon` | Icon in front of the title. |
| `end` | Trailing content on the title row, such as a badge. |
| `menu` | Popup menu, usually a `NavHeadingMenu`. The scope provides `close` and `focusRequest`. |

## TopNavMegaMenuFeaturedCard Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `string` | - | Card title. |
| `description` | `string` | - | Supporting line under the title. |
| `href` | `string` | - | Makes the whole card a link. With `linkLabel`, the link moves to the bottom of the card. |
| `image` | `string` | - | Image shown above the text. |
| `imageAlt` | `string` | - | Alternative text. Without it the image is decorative and skipped by assistive tech. |
| `linkLabel` | `string` | - | Action text at the bottom of the card. |
| `linkHref` | `string` | - | Destination of the action. Falls back to `href`. |
| `as` | `NavLinkComponent` | `'a'` | Link root. |
