Skip to main content
WireKit
Copy for LLM

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.

A row of open records

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.

One line

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.

<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 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, 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.

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 — switch between panels on one page rather than between pages
  • Navbar — the site's top navigation
  • Popover — the menu the links move into

Updated in WireKit v2.56.0 (2026-09-26)

Was this page helpful?

Thank you for your feedback!

Voting requires cookies or local storage. What we store