Bottom Nav
The tab bar app-shaped mobile layouts live on. WireKit's layout family had a navbar, a sidebar, a header and a footer — but nothing pinned to the bottom of a phone, which is where a thumb actually is.
Reserving room for it
The bar is position: fixed, so page content scrolls underneath it. Without
room reserved, the last thing on every page hides behind the nav.
Add wk-bottom-nav-offset to whatever scrolls:
<main class="wk-bottom-nav-offset">
…
</main>
<x-wirekit::bottom-nav label="Main">…</x-wirekit::bottom-nav>
That is opt-in on purpose: this component cannot know which element scrolls in
your layout, and padding the wrong box is worse than padding none. The offset
disappears at md along with the bar itself — add wk-bottom-nav-offset-always
if you kept the bar on desktop with :mobile-only="false".
Items
Each item is a link with an icon, a label and an optional badge:
<x-wirekit::bottom-nav label="Main">
<x-wirekit::bottom-nav.item href="/" label="Home" icon="home" :active="request()->is('/')" />
<x-wirekit::bottom-nav.item href="/inbox" label="Inbox" icon="envelope" badge="3" />
</x-wirekit::bottom-nav>
The badge goes into the item's accessible name — "Inbox, 3" — because "Inbox" and "Inbox, 3" are different claims and a reader who cannot see the dot deserves the number. The visual badge is then hidden from assistive tech, so it is announced once rather than twice.
Where it shows
By default the bar hides from md up, where a sidebar or a
navbar does this job — a bar pinned to the bottom of a
27-inch screen is a long way from the content it belongs to.
Pass :mobile-only="false" to keep it everywhere.
Props
<x-wirekit::bottom-nav>
| Prop | Type | Default | Description |
|---|---|---|---|
label |
string |
'Main' |
Names the nav landmark. |
mobileOnly |
bool |
true |
Hide from md up. |
interactive |
bool |
false |
Track the current tab client-side: clicking an item marks it active (no page load), keyed by label. Off by default — a real app usually drives active from its router. |
scope |
string|null |
null |
Class-scope override. |
<x-wirekit::bottom-nav.item>
| Prop | Type | Default | Description |
|---|---|---|---|
href |
string |
'#' |
Where it goes. |
label |
string |
'' |
Visible label, and the base of the accessible name. |
active |
bool |
false |
Marks this as the current page. |
icon |
string|null |
null |
Icon name. |
badge |
string|int|null |
null |
Count on the icon. Joins the accessible name. |
scope |
string|null |
null |
Class-scope override. |
Accessibility
- A real
<nav>landmark with a name, so a screen-reader user can jump to it. - The current tab carries
aria-current="page"and a marker line above it — the color is a third signal, never the only one (WCAG 1.4.1). - Items are at least 52px tall. A nav item is the primary control here, and a 32px tab on a phone is a tap people miss (WCAG 2.5.5).
- The bar pads itself by
env(safe-area-inset-bottom). The bottom of the viewport is not the bottom of the usable screen on a phone with a home indicator — without that padding the labels sit under it and the swipe-up gesture eats the taps. - The badge is announced once, as part of the item's name.
Keyboard Interaction
| Key | Action |
|---|---|
| Tab | Move through the tabs in order. |
| Enter | Follow the focused tab. |
The items are ordinary links, so they keep every behavior a link has — middle-click, open in a new tab, the status bar showing where it goes.