---
title: Overflow Nav
description: A wrapping row of links kept to a number of lines, with the links that do not fit behind a button that counts them.
visibility: guest
draft: false
---

# Overflow Nav

`<x-wirekit::overflow-nav>` shows a row of links that wraps onto at most `lines` rows, two by default. The links the rows have no room for move into a menu at the end of the last row, behind a button that shows how many it holds. The link marked `current` never moves into the menu, so the page on screen is always in the rows.

It suits a row of open records, recently viewed pages or filters, where the number of links changes and the width of the screen decides how many fit.

## Usage

Pass the links as `items`. Each one takes a `label` and an `href`, and at most one should be `current`.

:::preview{title="A row of open records"}
<x-wirekit::overflow-nav label="Open records" :items="[
    ['label' => 'Waxed leather boots', 'href' => '#boots'],
    ['label' => 'Canvas tote', 'href' => '#tote'],
    ['label' => 'Merino socks', 'href' => '#socks'],
    ['label' => 'Linen shirt', 'href' => '#shirt'],
    ['label' => 'Wool beanie', 'href' => '#beanie'],
    ['label' => 'Leather belt', 'href' => '#belt'],
    ['label' => 'Rain jacket', 'href' => '#jacket', 'current' => true],
    ['label' => 'Travel wallet', 'href' => '#wallet'],
    ['label' => 'Suede loafers', 'href' => '#loafers'],
    ['label' => 'Cotton scarf', 'href' => '#scarf'],
    ['label' => 'Denim apron', 'href' => '#apron'],
    ['label' => 'Silk tie', 'href' => '#tie'],
    ['label' => 'Hiking poles', 'href' => '#poles'],
    ['label' => 'Duffel bag', 'href' => '#duffel'],
    ['label' => 'Card holder', 'href' => '#cards'],
    ['label' => 'Straw hat', 'href' => '#hat'],
]" />
:::

## Lines

`lines` sets how many rows the links may take. With `lines="1"` the row never wraps, and everything that does not fit on one line goes into the menu.

:::preview{title="One line"}
<x-wirekit::overflow-nav label="Recently viewed" lines="1" :items="[
    ['label' => 'Overview', 'href' => '#overview', 'current' => true],
    ['label' => 'Orders', 'href' => '#orders'],
    ['label' => 'Customers', 'href' => '#customers'],
    ['label' => 'Products', 'href' => '#products'],
    ['label' => 'Invoices', 'href' => '#invoices'],
    ['label' => 'Shipping', 'href' => '#shipping'],
    ['label' => 'Returns', 'href' => '#returns'],
    ['label' => 'Reports', 'href' => '#reports'],
    ['label' => 'Settings', 'href' => '#settings'],
]" />
:::

## Links that navigate with Livewire

Give an item `attributes` for anything its anchor should carry, such as `wire:navigate`. The same attributes go on the link in the rows and on its copy in the menu.

```blade
<x-wirekit::overflow-nav label="Open records" :items="$records->map(fn ($record) => [
    'label' => $record->name,
    'href' => route('records.show', $record),
    'current' => $record->is($current),
    'attributes' => ['wire:navigate' => true],
])->all()" />
```

## How it decides what fits

The component lays every link out once, reads its width and replays the wrapping of the row in arithmetic. Links come off the end one at a time until the rest and the button fit in `lines` rows, so every row is full before anything moves into the menu. When only the current link would be left to move, nothing more moves, and the rows may then take one line more than `lines`.

Three details keep that measurement steady, and they matter if you build something like it yourself:

- **It measures in one task.** Showing every link through component state and measuring on the next tick lets the browser draw a frame in between; the row grows and shrinks, the resize observer sees it, and the row measures itself again on every frame. The component shows the links by hand, reads the widths and restores the styles before it sets any state.
- **`x-show` shows on the next frame.** It hides at once but shows one animation frame later, so a link shown through state and measured right after still reads as hidden. The measurement reads the inline styles it set itself.
- **Only the width asks for a new measurement.** The height changes every time a link moves into the menu, so the component measures again when the row's width changes or when links are added or removed, and never for a change of height.

Without JavaScript every link is shown, in as many rows as it takes, and there is no button.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `items` | `array` | `[]` | The links, in order. Each takes `label`, `href`, and optionally `current` (the page on screen, never moved into the menu) and `attributes` (extra attributes for the anchor) |
| `lines` | `int` | `2` | How many rows the links may take before the rest move into the menu |
| `label` | `string\|null` | `null` | The landmark's name. With a label the row is a `<nav>`; without one it is a plain list, so two rows on a page never share a nameless landmark |
| `scope` | `string\|null` | `null` | Scoped [personalization](/customization) key for the `row`, `link` and `menu-link` blocks |

## Accessibility

- The current link carries `aria-current="page"`, and it stays in the rows at every width.
- The button's accessible name counts the menu ("3 more links"), and its visible text is the count ("+3").
- The menu is a [popover](/components/popover), named "More links", with a focus trap while it is open. `Escape` closes it and returns focus to the button.
- A link that moves into the menu leaves the rows, so a screen reader meets every link exactly once.

## Keyboard Interaction

| Key | Action |
|-----|--------|
| `Tab` / `Shift+Tab` | Move through the links in the rows, then to the button |
| `Enter` (on a link) | Follow the link |
| `Enter` / `Space` (on the button) | Open or close the menu |
| `Tab` / `Shift+Tab` (inside the open menu) | Move through the links in the menu, which keeps focus while it is open |
| `Escape` | Close the menu and return focus to the button |

*Every entry is a link with the browser's own keyboard behavior; the menu is a [popover](/components/popover).*

## Design Tokens

| Token | Used for |
| --- | --- |
| `--gap-wk-xs` | Space between links, and between rows |
| `--padding-wk-x-sm`, `--padding-wk-y-xs` | Padding of a link |
| `--radius-wk-md` | Corner radius of a link |
| `--color-wk-text-muted` | A link that is not current |
| `--color-wk-text`, `--color-wk-bg-muted` | The current link, and a link under the pointer |
| `--ring-wk-width`, `--color-wk-ring` | The focus ring |

## See Also

- [Tabs](/components/tabs) — switch between panels on one page rather than between pages
- [Navbar](/components/navbar) — the site's top navigation
- [Popover](/components/popover) — the menu the links move into
