Skip to main content
Copy for LLM

Navbar

The <x-wirekit::navbar> component creates a responsive top navigation bar with brand area, navigation items, and action slots. It automatically collapses into a hamburger menu below the md breakpoint for mobile devices.

Building a signed-in dashboard? navbar is the top-nav shell for marketing sites and top-nav apps. For a sidebar dashboard layout use App Shell instead — and don't nest navbar inside the header of an app-shell that has a sidebar or rail slot, since both would then render their own mobile menu.

Usage

Responsive Navbar

In a real Laravel app, wrap the brand content in an <a href="/"> and bind each item's :active prop to request()->is('dashboard') (or similar) so the current page is highlighted automatically.

Variants

Default

The default variant has a subtle bottom border:

Default Variant

Bordered

Adds a visible border on all sides with a slight shadow:

Bordered Variant

Transparent

No background, no border -- suitable for hero sections or overlaying images:

Transparent Variant

Pin the navbar to the top of the viewport on scroll:

<x-wirekit::navbar :sticky="true">
    ...
</x-wirekit::navbar>

This applies position: sticky; top: 0; and z-index: var(--z-wk-chrome) — 55, which is ABOVE the dropdown layer (50) on purpose. A popover opened in page content is a teleported panel at that layer and would otherwise paint over the bar; a panel anchored inside the bar opens downward and never overlaps it, so nothing is lost, and a modal is still above. The surface is --color-wk-bg-elevated, opaque — there is no backdrop-filter.

An element that takes the focus, or that a fragment link brings into view, comes to rest below a sticky navbar rather than under it: the bar tells the page how much of the top it covers (keeping the focus clear of a pinned bar).

Brand Slot

The brand slot renders on the left side and is always visible (both desktop and mobile):

Navbar with Brand and Actions

Active Items

Mark the currently active navigation item. Active items receive accent-colored text and an underline indicator, with aria-current="page" set automatically:

Active Navigation Item

In your Blade templates, use dynamic active detection:

<x-wirekit::navbar.item href="/dashboard" :active="request()->is('dashboard')">
    Dashboard
</x-wirekit::navbar.item>

Mobile Behavior

Below the md breakpoint (768px), navigation items collapse behind a hamburger button. The hamburger button:

  • Uses the menu icon (three horizontal lines)
  • Toggles aria-expanded between "true" and "false"
  • Has aria-label="Toggle navigation" for screen readers
  • Reveals a vertical dropdown panel with all navigation items
Simulated Mobile Layout (forceMobile)

The preview above uses :force-mobile="true" to render the mobile layout unconditionally — the hamburger button is always visible, the desktop item row is always hidden. This is purely a preview/testing aid so the mobile state can be demonstrated without resizing the browser. In a real app, omit force-mobile and the navbar will collapse automatically below the md breakpoint (768px). Click the hamburger button to open the mobile menu.

No additional markup is needed for the responsive behavior — the breakpoint-based mobile menu is fully automatic.

A row that scrolls instead of a menu

Some bars are switched between rather than opened: an operator jumps from screen to screen and wants to see where they are. mobile="scroll" keeps the entries as one row at every width. On a narrow screen the row scrolls sideways, and the entry for the current page (an active item, which carries aria-current="page") is brought into view when the page loads and whenever the row changes width. There is no menu toggle in this mode.

density="compact" sets the entries in the small text size with less padding and draws the ones you are not on in the muted color, so in a long row the current entry is the one that stands out. Every navbar.item inside reads it from the bar.

Eleven entries, one row

The row scrolls by touch, wheel and trackpad, and a keyboard reaches every entry with Tab, which scrolls each into view as it takes focus. It draws no scrollbar: the row is the bar, and a track under it would read as a second rule. Instead, an edge with more entries behind it fades out, and an edge the row rests against stays sharp, so the row reads as one that scrolls. The fade is the same edge mask Scroll Area uses, and it is dropped while a link in the row has keyboard focus. The current entry is brought in by moving the row alone, so a page loaded half-way down stays where it is.

With Dropdown Submenus

For navigation items with dropdown sub-menus, combine the navbar with Dropdown. Use a ghost button as the trigger and include a chevron icon so users recognize the item has a submenu:

Navbar with Dropdown Submenu

Multiple Dropdown Menus

For a navbar with several dropdown sections, repeat the pattern for each submenu. Each chevron rotates downward to signal an expandable menu:

Navbar with Multiple Dropdown Menus

For rich mega-menu panels with multiple columns and descriptions, see the Navigation Menu component.

Overflow Behavior

When there are too many navigation items, they collapse into the mobile hamburger menu below the md breakpoint (768px). On desktop, items wrap naturally. To keep the bar on a single line, move the rarely-used items into a "More" dropdown — the example below shows four primary items followed by six more tucked behind the dropdown trigger, which is a scalable pattern even when a marketing site accumulates a long list of pages.

Navbar with Overflow Dropdown

For navigation trees beyond ten items or grouped categories, consider upgrading to the Navigation Menu component — it ships flyout panels that can render multi-column mega-menus with headings and descriptions.

Width & Layout

The navbar stretches to full width, and its content does too by default — container is false. Set container to wrap the inner row in a max-width column so the bar's chrome stays edge-to-edge while its content lines up with a container-wrapped body; max then picks the tier. The width comes from the --size-wk-container-* tokens, the same ones the container component reads — not from a max-w-7xl utility, which the component emits nowhere.

Behavior

  • Auto-collapse: navigation items are hidden behind a hamburger below the md breakpoint (768px)
  • Brand and actions are always visible on both desktop and mobile
  • Sticky mode uses position: sticky at --z-wk-chrome, on the opaque --color-wk-bg-elevated surface the bar always carries. No backdrop-filter — content scrolls behind it, not through it
  • Livewire SPA navigation (wire:navigate) automatically closes the mobile menu
  • Transitions use height animation for smooth mobile menu reveal

Props

<x-wirekit::navbar>

Prop Type Default Description
variant string 'default' Visual style: 'default', 'bordered', 'transparent'
sticky bool false Pin to top of viewport on scroll
forceMobile bool false Render the mobile layout unconditionally (hamburger visible, desktop item row hidden). Useful for previews and embedded contexts narrower than the md breakpoint. No effect with mobile="scroll", which has one layout at every width
mobile 'menu' | 'scroll' 'menu' What the entries do below md. menu folds them behind a toggle; scroll keeps them one sideways-scrolling row and brings the current entry into view. See A row that scrolls instead of a menu
density 'default' | 'compact' 'default' How tightly the entries sit. compact sets them in the small text size with less padding and mutes the ones you are not on; every navbar.item inside reads it
container bool false Wrap the inner row in a max-width container so the nav content aligns with page content instead of spanning the full viewport width.
max string|null null Container tier when container is set — 'sm', 'md', 'lg', 'xl', '2xl', 'full' (reads --size-wk-container-*).
scope string|null null Scoped personalization key

<x-wirekit::navbar.item>

Prop Type Default Description
href string '#' Link destination
active bool false Highlights as current page
scope string|null null Scoped personalization key

Sub-Components

Component Purpose
navbar.item A single navigation link

Named Slots

Slot Purpose
brand Logo or brand name (left side, always visible)
actions CTA buttons or user actions (right side, always visible)
default Navigation items (collapse on mobile)

Accessibility

  • Navbar wrapper: a <nav> landmark named Main navigation (translated with the app locale)
  • Active item: aria-current="page"
  • Hamburger button: aria-label="Toggle navigation", aria-expanded (dynamic), aria-controls (linked to collapsible menu ID)
  • Mobile menu: id="wk-navbar-mobile", or <your-id>-mobile when you give the navbar an id. A second navbar on the same page gets wk-navbar-mobile-2, so each hamburger's aria-controls keeps pointing at its own menu. The menu is shown and hidden by Alpine (x-show), not by the hidden attribute — so it is absent from the accessibility tree while collapsed either way, but a stylesheet cannot force it open by overriding [hidden]
  • All items are standard <a> elements -- fully accessible by default
  • Focus ring visible on all focusable elements via focus-visible:ring-[length:var(--ring-wk-width)]

Keyboard Interaction

The navbar is a layout wrapper. Its links and buttons, the mobile-menu toggle among them, keep their own keys, and the bar adds Escape for the mobile menu:

Key Action
Tab Move focus through navbar items sequentially
Enter / Space Activate the focused link, or open and close the mobile menu from its button. Opening moves focus to the menu's first entry, so the next Tab goes on through the menu
Escape Close the mobile menu when it is open. Focus inside the menu moves to the menu button

Pitfalls

  • Don't put a <x-wirekit::dropdown> inside a <x-wirekit::navbar.item>. The dropdown's portal-based rendering escapes the navbar's flex context and the trigger's keyboard handlers conflict with the navbar item's. Use <x-wirekit::navigation-menu> for nested navigation.
  • Don't render a navbar without a <x-wirekit::brand> for screen readers. The brand acts as the page-level wayfinding landmark — without it, the navbar's <nav aria-label="Main"> is unmoored.

Design Tokens

Element Token
Bar background --color-wk-bg-elevated
Bar border --color-wk-border / --border-wk-width
Bar shadow (bordered variant) --shadow-wk-sm
Bar padding --padding-wk-x-lg
Item text --color-wk-text
Item hover background --color-wk-bg-hover
Item active text --color-wk-accent-text
Mobile menu background --color-wk-bg-elevated
Mobile menu border --color-wk-border
Hamburger icon color --color-wk-text
Font family --font-wk-sans
Font size --text-wk-md
Transition --transition-wk-duration
Bar surface (sticky and not) --color-wk-bg-elevated, opaque
Sticky stacking layer --z-wk-chrome

Personalization

Override defaults in config/wirekit.php:

'components' => [
    'navbar' => [
        'variant' => 'bordered',
        'sticky' => true,
    ],
],

Scoped Personalization

<x-wirekit::navbar scope="marketing">
    ...
</x-wirekit::navbar>
// In a service provider's boot() method. A closure receives the shipped classes, so the
// component keeps them; a plain string would replace them outright.
WireKit::scope('marketing', [
    'navbar' => ['classes' => [
        'base' => fn (string $vendor): string => $vendor.' max-w-7xl mx-auto',
    ]],
]);

Usage & Conventions

Prop conventions — this component uses one or more of the shared semantic prop names (intent / variant / tone / surface). See Prop naming conventions for the canonical vocabulary, alias matrix, and decision tree.

Further Reading

Updated in WireKit v2.66.0 (2026-10-13)

Was this page helpful?

Thank you for your feedback!

Voting requires cookies or local storage. What we store