# or
yarn add @zag-js/navigation-menu @zag-js/solid
```

## Anatomy

To set up the navigation menu correctly, you'll need to understand its anatomy
and how we name its parts.

> Each part includes a `data-part` attribute to help identify them in the DOM.



## Usage

First, import the navigation menu package into your project

```jsx
import * as navigationMenu from "@zag-js/navigation-menu"
```

The navigation menu package exports two key functions:

- `machine` â The state machine logic for the navigation menu widget.
- `connect` â The function that translates the machine's state to JSX attributes
  and event handlers.

> You'll need to provide a unique `id` to the `useMachine` hook. This is used to
> ensure that every part has a unique identifier.

Next, import the required hooks and functions for your framework and use the
navigation menu machine in your project ð¥

```jsx
import * as navigationMenu from "@zag-js/navigation-menu"
import { useMachine, normalizeProps } from "@zag-js/solid"
import { createMemo, createUniqueId } from "solid-js"

export function NavigationMenu() {
  const service = useMachine(navigationMenu.machine, {
    id: createUniqueId(),
  })

  const api = createMemo(() => navigationMenu.connect(service, normalizeProps))

  return (
    <nav {...api().getRootProps()}>
      <ul {...api().getListProps()}>
        {/* Item with dropdown content */}
        <li {...api().getItemProps({ value: "products" })}>
          <button {...api().getTriggerProps({ value: "products" })}>
            Products
          </button>
          <div {...api().getContentProps({ value: "products" })}>
            <a {...api().getLinkProps({ value: "products" })} href="/analytics">
              Analytics
            </a>
            <a {...api().getLinkProps({ value: "products" })} href="/marketing">
              Marketing
            </a>
          </div>
        </li>

        {/* Simple link item */}
        <li {...api().getItemProps({ value: "pricing" })}>
          <a {...api().getLinkProps({ value: "pricing" })} href="/pricing">
            Pricing
          </a>
        </li>
      </ul>
    </nav>
  )
}
```

The basic pattern places content directly within each item. This is suitable for
simple dropdown menus where each dropdown appears below its trigger.

### Advanced pattern with viewport

The viewport pattern uses a shared viewport container for all content. This
enables smooth transitions and better performance for complex navigation
layouts.

In this pattern:

- Content is rendered inside a shared `viewport` element
- The viewport automatically positions itself relative to the active trigger
- You must include `triggerProxy` and `viewportProxy` for proper focus
  management

```jsx
import * as navigationMenu from "@zag-js/navigation-menu"
import { useMachine, normalizeProps } from "@zag-js/solid"
import { createMemo, createUniqueId } from "solid-js"

export function NavigationMenu() {
  const service = useMachine(navigationMenu.machine, { id: createUniqueId() })
  const api = createMemo(() => navigationMenu.connect(service, normalizeProps))

  return (
    <nav {...api().getRootProps()}>
      <div {...api().getIndicatorTrackProps()}>
        <ul {...api().getListProps()}>
          {/* Item with trigger */}
          <li {...api().getItemProps({ value: "products" })}>
            <button {...api().getTriggerProps({ value: "products" })}>
              Products
            </button>
            {/* Focus management proxies */}
            <span {...api().getTriggerProxyProps({ value: "products" })} />
            <span {...api().getViewportProxyProps({ value: "products" })} />
          </li>

          {/* Simple link */}
          <li {...api().getItemProps({ value: "pricing" })}>
            <a {...api().getLinkProps({ value: "pricing" })} href="/pricing">
              Pricing
            </a>
          </li>

          {/* Indicator */}
          <div {...api().getIndicatorProps()}>
            <div {...api().getArrowProps()} />
          </div>
        </ul>
      </div>

      {/* Shared viewport for all content */}
      <div {...api().getViewportPositionerProps()}>
        <div {...api().getViewportProps()}>
          {/* Content for products */}
          <div {...api().getContentProps({ value: "products" })}>
            <a {...api().getLinkProps({ value: "products" })} href="/analytics">
              Analytics
            </a>
            <a {...api().getLinkProps({ value: "products" })} href="/marketing">
              Marketing
            </a>
          </div>
        </div>
      </div>
    </nav>
  )
}
```

**When to use viewport pattern:**

- Complex navigation with varying content sizes
- Smooth animated transitions between different content
- Header navigation bars (like on e-commerce sites)
- When you want a single shared container for all dropdowns

### Controlling the navigation menu

To control which item is currently open, pass the `value` and `onValueChange`
properties to the machine.

```jsx {1,4-8}
import { createSignal } from "solid-js"

export function NavigationMenu() {
  const [value, setValue] = createSignal("")

  const service = useMachine(navigationMenu.machine, {
    id: createUniqueId(),
    value: value(),
    onValueChange: (details) => setValue(details.value),
  })

  const api = createMemo(() => navigationMenu.connect(service, normalizeProps))

  return (
    <div>
      <button onClick={() => setValue("products")}>Open Products</button>
      <button onClick={() => setValue("")}>Close All</button>

      <nav {...api().getRootProps()}>{/* ... navigation items ... */}</nav>
    </div>
  )
}
```

### Listening for value changes

When the open item changes, the `onValueChange` callback is invoked with the new
value.

```jsx {3-6}
const service = useMachine(navigationMenu.machine, {
  id: "nav",
  onValueChange(details) {
    // details => { value: string }
    console.log("Current open item:", details.value)
  },
})
```

### Adding an animated indicator

To show a visual indicator that animates to the active trigger, render the
indicator within the list container:

```jsx {3-5}
<nav {...api().getRootProps()}>
  <div {...api().getListProps()}>
    {/* ... items ... */}

    <div {...api().getIndicatorProps()}>
      <div {...api().getArrowProps()} />
    </div>
  </div>
</nav>
```

The indicator automatically transitions to match the active trigger's position
and size using CSS variables.

### Configuring hover delays

You can customize the delay before opening and closing on hover:

```jsx {2-3}
const service = useMachine(navigationMenu.machine, {
  openDelay: 300, // Delay before opening on hover (default: 200ms)
  closeDelay: 400, // Delay before closing on pointer leave (default: 300ms)
})
```

**Tip**: Longer delays provide a more forgiving user experience but can feel
less responsive.

### Disabling hover or click triggers

You can disable hover or click triggers independently:

```jsx {2-6}
const service = useMachine(navigationMenu.machine, {
  disableHoverTrigger: true, // Only open on click
  // OR
  disableClickTrigger: true, // Only open on hover
  // OR
  disablePointerLeaveClose: true, // Prevents closing when pointer leaves
})
```

- `disableHoverTrigger` â Prevents opening on hover (click only)
- `disableClickTrigger` â Prevents opening on click (hover only)
- `disablePointerLeaveClose` â Prevents closing when pointer leaves

### Changing orientation

The default orientation is horizontal. To create a vertical navigation menu:

```jsx {2}
const service = useMachine(navigationMenu.machine, {
  orientation: "vertical",
})
```

This affects keyboard navigation (arrow keys) and indicator positioning.

### Disabling items

To disable a navigation item, pass `disabled: true` to the item props:

```jsx
<div {...api.getItemProps({ value: "products", disabled: true })}>
  <button {...api.getTriggerProps({ value: "products", disabled: true })}>
    Products
  </button>
</div>
```

Disabled items cannot be opened and are skipped during keyboard navigation.

### Indicating current page

To highlight the current page link, use the `current` prop:

```jsx
<a {...api.getLinkProps({ value: "products", current: true })}>Products</a>
```

This adds `data-current` attribute and `aria-current="page"` for accessibility.

### RTL support

The navigation menu supports right-to-left languages. Set the `dir` property to
`rtl`:

```jsx {2}
const service = useMachine(navigationMenu.machine, {
  dir: "rtl",
})
```

## Styling guide

Earlier, we mentioned that each navigation menu part has a `data-part` attribute
added to them to select and style them in the DOM.

### Open and closed states

When content is open or closed, it receives a `data-state` attribute:

```css
[data-part="content"][data-state="open|closed"] {
  /* Styles for open or closed content */
}

[data-part="trigger"][data-state="open|closed"] {
  /* Styles for open or closed trigger */
}

[data-part="viewport"][data-state="open|closed"] {
  /* Styles for viewport open/closed state */
}
```

### Selected item state

When an item is selected (open), it receives `data-state="open"`:

```css
[data-part="item"][data-state="open"] {
  /* Styles for open item */
}
```

### Disabled state

Disabled items have a `data-disabled` attribute:

```css
[data-part="item"][data-disabled] {
  /* Styles for disabled items */
}

[data-part="trigger"][data-disabled] {
  /* Styles for disabled triggers */
}
```

### Orientation styles

All parts have a `data-orientation` attribute:

```css
[data-part="root"][data-orientation="horizontal|vertical"] {
  /* Orientation-specific styles */
}

[data-part="list"][data-orientation="horizontal"] {
  display: flex;
  flex-direction: row;
}

[data-part="list"][data-orientation="vertical"] {
  display: flex;
  flex-direction: column;
}
```

### Current link state

Links marked as current have a `data-current` attribute:

```css
[data-part="link"][data-current] {
  /* Styles for current page link */
}
```

### Styling the indicator

The indicator uses CSS variables for positioning and sizing:

```css
[data-part="indicator"] {
  position: absolute;
  transition:
    translate 250ms ease,
    width 250ms ease,
    height 250ms ease;
}

[data-part="indicator"][data-orientation="horizontal"] {
  left: 0;
  translate: var(--trigger-x) 0;
  width: var(--trigger-width);
}

[data-part="indicator"][data-orientation="vertical"] {
  top: 0;
  translate: 0 var(--trigger-y);
  height: var(--trigger-height);
}
```

### Styling the viewport

The viewport uses CSS variables for positioning and sizing:

```css
[data-part="viewport"] {
  position: absolute;
  width: var(--viewport-width);
  height: var(--viewport-height);
  transition:
    width 300ms ease,
    height 300ms ease;
}
```

### Arrow styling

The arrow can be styled using CSS variables:

```css
[data-part="root"] {
  --arrow-size: 20px;
}

[data-part="arrow"] {
  width: var(--arrow-size);
  height: var(--arrow-size);
  background: white;
  rotate: 45deg;
}
```

### Motion attributes

When using the viewport pattern, content elements receive `data-motion`
attributes for directional animations:

```css
[data-part="content"][data-motion="from-start"] {
  animation: slideFromStart 250ms ease;
}

[data-part="content"][data-motion="from-end"] {
  animation: slideFromEnd 250ms ease;
}

[data-part="content"][data-motion="to-start"] {
  animation: slideToStart 250ms ease;
}

[data-part="content"][data-motion="to-end"] {
  animation: slideToEnd 250ms ease;
}
```

**Tip**: The motion direction indicates where the content is coming from
(from-start/from-end) or going to (to-start/to-end), enabling context-aware
animations when switching between items.

## Methods and Properties

### Machine Context

The navigation menu machine exposes the following context properties:

**`ids`**
Type: `Partial<{ root: string; list: string; item: string; trigger: (value: string) => string; content: (value: string) => string; viewport: string; }>`
Description: The ids of the elements in the machine.

**`value`**
Type: `string`
Description: The controlled value of the navigation menu

**`defaultValue`**
Type: `string`
Description: The default value of the navigation menu.
Use when you don't want to control the value of the menu.

**`onValueChange`**
Type: `(details: ValueChangeDetails) => void`
Description: Function called when the value of the menu changes

**`openDelay`**
Type: `number`
Description: The delay before the menu opens

**`closeDelay`**
Type: `number`
Description: The delay before the menu closes

**`disableClickTrigger`**
Type: `boolean`
Description: Whether to disable the click trigger

**`disableHoverTrigger`**
Type: `boolean`
Description: Whether to disable the hover trigger

**`disablePointerLeaveClose`**
Type: `boolean`
Description: Whether to disable the pointer leave close

**`dir`**
Type: `"ltr" | "rtl"`
Description: The document's text/writing direction.

**`id`**
Type: `string`
Description: The unique identifier of the machine.

**`getRootNode`**
Type: `() => ShadowRoot | Node | Document`
Description: A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.

**`orientation`**
Type: `"horizontal" | "vertical"`
Description: The orientation of the element.

### Machine API

The navigation menu `api` exposes the following methods:

**`value`**
Type: `string`
Description: The current value of the menu

**`setValue`**
Type: `(value: string) => void`
Description: Sets the value of the menu

**`open`**
Type: `boolean`
Description: Whether the menu is open

**`isViewportRendered`**
Type: `boolean`
Description: Whether the viewport is rendered

**`getViewportNode`**
Type: `() => HTMLElement`
Description: Gets the viewport node element

**`orientation`**
Type: `Orientation`
Description: The orientation of the menu

**`reposition`**
Type: `VoidFunction`
Description: Function to reposition the viewport

### Data Attributes

**`Root`**

**`data-scope`**: navigation-menu
**`data-part`**: root
**`data-orientation`**: The orientation of the navigation-menu

**`List`**

**`data-scope`**: navigation-menu
**`data-part`**: list
**`data-orientation`**: The orientation of the list

**`Item`**

**`data-scope`**: navigation-menu
**`data-part`**: item
**`data-value`**: The value of the item
**`data-state`**: "open" | "closed"
**`data-orientation`**: The orientation of the item
**`data-disabled`**: Present when disabled

**`Indicator`**

**`data-scope`**: navigation-menu
**`data-part`**: indicator
**`data-state`**: "open" | "closed"
**`data-orientation`**: The orientation of the indicator

**`Arrow`**

**`data-scope`**: navigation-menu
**`data-part`**: arrow
**`data-orientation`**: The orientation of the arrow

**`Trigger`**

**`data-scope`**: navigation-menu
**`data-part`**: trigger
**`data-trigger-proxy-id`**: 
**`data-value`**: The value of the item
**`data-state`**: "open" | "closed"
**`data-disabled`**: Present when disabled

**`TriggerProxy`**

**`data-scope`**: navigation-menu
**`data-part`**: trigger-proxy
**`data-trigger-proxy`**: 
**`data-trigger-id`**: 

**`Link`**

**`data-scope`**: navigation-menu
**`data-part`**: link
**`data-value`**: The value of the item
**`data-current`**: Present when current

**`Content`**

**`data-scope`**: navigation-menu
**`data-part`**: content
**`data-state`**: "open" | "closed"
**`data-orientation`**: The orientation of the content
**`data-value`**: The value of the item

**`ViewportPositioner`**

**`data-scope`**: navigation-menu
**`data-part`**: viewport-positioner
**`data-orientation`**: The orientation of the viewportpositioner
**`data-align`**: 

**`Viewport`**

**`data-scope`**: navigation-menu
**`data-part`**: viewport
**`data-state`**: "open" | "closed"
**`data-orientation`**: The orientation of the viewport
**`data-align`**: 

**`ItemIndicator`**

**`data-scope`**: navigation-menu
**`data-part`**: item-indicator
**`data-state`**: "open" | "closed"
**`data-orientation`**: The orientation of the item
**`data-value`**: The value of the item

### CSS Variables

<CssVarTable name="navigation-menu" />

## Accessibility

### Keyboard Interactions

**`ArrowDown`**
Description: When focus is on trigger (vertical orientation), moves focus to the next trigger.

**`ArrowUp`**
Description: When focus is on trigger (vertical orientation), moves focus to the previous trigger.

**`ArrowRight`**
Description: <span>When focus is on trigger (horizontal orientation), moves focus to the next trigger.<br />When focus is on content, moves focus to the next link.</span>

**`ArrowLeft`**
Description: <span>When focus is on trigger (horizontal orientation), moves focus to the previous trigger.<br />When focus is on content, moves focus to the previous link.</span>

**`Home`**
Description: <span>When focus is on trigger, moves focus to the first trigger.<br />When focus is on content, moves focus to the first link.</span>

**`End`**
Description: <span>When focus is on trigger, moves focus to the last trigger.<br />When focus is on content, moves focus to the last link.</span>
The number input provides controls for editing, incrementing or decrementing
numeric values using the keyboard or pointer.

## Resources


[Latest version: v1.33.1](https://www.npmjs.com/package/@zag-js/number-input)
[Logic Visualizer](https://zag-visualizer.vercel.app/number-input)
[Source Code](https://github.com/chakra-ui/zag/tree/main/packages/machines/number-input)



**Features**

- Based on the spinbutton pattern
- Supports using the scroll wheel to increment and decrement the value
- Handles floating point rounding errors when incrementing, decrementing, and
  snapping to step
- Supports pressing and holding the spin buttons to continuously increment or
  decrement
- Supports rounding value to specific number of fraction digits
- Support for scrubbing interaction

## Installation

To use the number input machine in your project, run the following command in
your command line:

```bash
npm install @zag-js/number-input @zag-js/solid