# Navbar

> Top navigation bar with automatic cart state, mobile menu, and full design freedom via data-lx-nav tags.

Canonical URL: https://fa7e86e3d553:3005/islands/navigation/navbar

> Fully customizable navigation bar. Two modes: **Hydration mode** (data-lx-nav tags — complete design freedom) or **Legacy mode** (props-driven rendering).

## Preview

**Category**: Navigation

---

## Hydration Mode (Recommended)

Generate any HTML/CSS you want. Place `data-lx-nav` tags on functional elements. The island attaches behavior (cart state, mobile toggle, sticky scroll) without touching your design.

### Required Tags

| Tag | Required | Purpose |
|-----|----------|---------|
| `data-lx-nav="root"` | Yes | Root nav element — sticky/scroll behavior attaches here |
| `data-lx-nav="cart-trigger"` | Yes* | Cart button — click opens Cart V2 or navigates |
| `data-lx-nav="cart-count"` | Yes* | Badge — textContent auto-updated from cart state |
| `data-lx-nav="mobile-trigger"` | Yes | Hamburger button — click toggles mobile panel |
| `data-lx-nav="mobile-panel"` | Yes | Mobile menu container — toggled via `lx-open` class |

*Not required if `hideCart: true` in props or `data-lx-hide-cart` attribute present.

### Optional Tags

| Tag | Purpose |
|-----|---------|
| `data-lx-nav="logo"` | Logo element (informational) |
| `data-lx-nav="link"` | Nav links (for analytics) |
| `data-lx-nav="dropdown-trigger"` | Hover opens associated dropdown |
| `data-lx-nav="dropdown-panel"` | Dropdown content (paired with trigger via parent) |
| `data-lx-nav="cta"` | CTA button (informational) |

### Behavior Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| sticky | boolean | true | Fixed positioning with scroll behavior |
| cartMode | "drawer" \| "link" | "drawer" | Legacy drawer mode or navigate to /cart |
| cartUrl | string | "/cart" | URL when cartMode="link" |
| transparent | boolean | false | Transparent bg until scroll |
| offsetTop | string | "0" | CSS top offset when sticky |
| hideCart | boolean | false | Skip cart-trigger/cart-count requirement |

### Full Example (Hydration Mode)

```html
<lx-island name="Navbar">
  <script type="application/json">
{
  "logo": {},
  "links": [
    {
      "label": "example-label",
      "url": "example-url"
    }
  ]
}
  </script>
</lx-island>
```

### CSS Contract

The island toggles `lx-open` class on the mobile panel. Include in your section CSS:

```css
[data-lx-nav="mobile-panel"] { display: none; }
[data-lx-nav="mobile-panel"].lx-open { display: block; }
```

Or use any animation (transform, opacity, max-height).

### Dropdown Example

```html
<div class="relative" >
  <a href="/shop" data-lx-nav="dropdown-trigger" class="text-sm font-medium">Shop ▾</a>
  <div data-lx-nav="dropdown-panel" class="absolute top-full left-0 mt-2 bg-white shadow-lg rounded-lg p-4 min-w-48">
    <a href="/collections/new" class="block py-2 text-sm">New Arrivals</a>
    <a href="/collections/sale" class="block py-2 text-sm">Sale</a>
  </div>
</div>
```

---

## Legacy Mode (Props-Driven)

If no `data-lx-nav` tags are found in the island HTML, the component renders its own React-based navbar from props.

### Props (Legacy)

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| logo | object | yes | - | `{src?, html?, alt?, url?}` — image or custom HTML |
| links | array | yes | - | `[{label, url, children?}]` |
| cartCount | number | no | 0 | Cart badge (auto-syncs with store) |
| transparent | boolean | no | false | Transparent until scroll |
| sticky | boolean | no | true | Fixed positioning |
| offsetTop | string | no | "0" | Top offset |
| style | object | no | {} | NavbarStyle (15 fields) |
| cta | object | no | - | `{label, url}` accent button |
| cart | object | no | - | `{icon?, svg?, image?, label?, badgeColor?}` custom cart icon |
| hideCart | boolean | no | false | Hide cart icon |

#### Logo Options

The `logo` prop supports two modes — provide at least one of `src` or `html`:

| Field | Type | Description |
|-------|------|-------------|
| src | string | Image URL (renders `<img>`) |
| html | string | Custom HTML — text, SVG, gradient text, anything |
| alt | string | Alt text (for image mode) |
| url | string | Link URL (default "/") |

```html
<lx-island name="Navbar">
  <script type="application/json">
{
  "logo": {},
  "links": [
    {
      "label": "example-label",
      "url": "example-url"
    }
  ]
}
  </script>
</lx-island>
```

#### Cart Icon Options

The `cart` prop lets you override the default bag icon. All custom icons still emit `cart:open` on click — DrawerShell opens regardless of icon used.

| Field | Type | Description |
|-------|------|-------------|
| icon | "bag" \| "cart" \| "basket" | Predefined icon variant |
| svg | string | Custom SVG markup |
| image | string | Custom icon image URL |
| label | string | Aria-label override |
| badgeColor | string | Override accent color for badge dot |

```html
<lx-island name="Navbar">
  <script type="application/json">
{
  "logo": {},
  "links": [
    {
      "label": "example-label",
      "url": "example-url"
    }
  ]
}
  </script>
</lx-island>
```

### Legacy Example

```html
<lx-island name="Navbar">
  <script type="application/json">
{
  "logo": {},
  "links": [
    {
      "label": "example-label",
      "url": "example-url"
    }
  ]
}
  </script>
</lx-island>
```

---

## Cart Behavior

In both modes, cart count auto-syncs with the shared cart state:
- When a product is added via BuyBox/QuickAdd → badge updates instantly
- New pages → click opens the effective Cart V2 profile; Cart V2 is enabled by default
- Legacy `cartMode: "drawer"` → click emits `cart:open` → CartDrawer slides in
- `cartMode: "link"` → click navigates to `cartUrl` (default "/cart")

**CartDrawer is required only for legacy pages** using `cartMode: "drawer"`.

## Validation

The publish validator enforces (hydration mode only):
- `data-lx-nav="root"` present
- `data-lx-nav="cart-trigger"` + `data-lx-nav="cart-count"` present (unless hideCart)
- `data-lx-nav="mobile-trigger"` + `data-lx-nav="mobile-panel"` present

Missing tags → publish blocked with actionable error message.

## Related Islands

- [SiteHeader](/islands/navigation/site-header) — Combined announcement + navbar
- [Footer](/islands/navigation/footer) — Page footer (also supports hydration mode)
- [CartDrawer](/islands/cart/cart-drawer) — Legacy Cart V1 alternative; new
  pages use the configured Cart V2 profile
