BottomNav
A thumb-reachable bottom tab bar: a real tablist with roving focus and an accent indicator.
Live demo
BottomNav is the tab bar that pairs with MobileShell the way Statusbar pairs with AppShell: the app's top-level sections, sitting where a thumb actually reaches.
It renders the tablist from its tabs through its own fragment, like Tabs and Segmented, so a mod can reshape a tab the same way it can reshape any other control.
The runtime adds what markup can't: a roving tabindex, so the whole bar is a single tab stop in the page with the arrow keys (plus Home / End) moving between sections inside it, rather than every tab being its own stop to tab past.
Each tab takes an optional icon and a badge. The selected one is marked by an accent bar as well as by color, so which section you're in never rests on hue alone.
When to use
How this component composes with the rest of the set.
Props
3 props, straight from the manifest.
| Prop | Type | Default | Bindings | Description |
|---|---|---|---|---|
Appearance
States
selected
The current section: accent-colored, and marked by the accent bar above it.
Anatomy
The named parts that make up the component, with their selectors.
bar
The tab bar itself: an equal-column grid, so any number of sections divide the width evenly. Absorbs the bottom safe-area inset so nothing sits under a home indicator.
item
A tab: an icon over a label, with the whole cell as the touch target rather than just the glyph.
indicator
The accent bar over the selected tab: the non-color cue that says which section is current.
badge
The optional count on a tab, for an unread or pending total.
Tokens & coverage
What the component consumes, checked live against what the algorithm produces.
Live coverage check against the xtyle-default register
(derive(xtyleDefault, { anchors }) →
coverComponent(manifest, register)). Every token this component
consumes must be a key the algorithm produces.
--accent
--accent-fg
--accent-text
--bg-1
--border-thick
--border-thin
--duration-fast
--ease-standard
--fg-3
--line
--radius-full
--radius-sm
--ring
--space-1
--space-2
--space-4
--space-6
--space-8
--text-xs
--weight-medium
--weight-semibold
Accessibility
Code
Sections
A tab bar over the app's top-level sections. Arrow keys move between them; change reports the new value.
<xtyle-bottom-nav
value="inbox"
label="Sections"
tabs='[{"value":"inbox","label":"Inbox","icon":"folder","badge":3},
{"value":"threads","label":"Threads","icon":"menu"},
{"value":"you","label":"You","icon":"gear"}]'
></xtyle-bottom-nav>
<script>
document.querySelector("xtyle-bottom-nav")
.addEventListener("change", (e) => show(e.target.value));
</script>
<script lang="ts">
import { BottomNav } from "@xtyle/svelte";
let section = $state("inbox");
const tabs = [
{ value: "inbox", label: "Inbox", icon: "folder", badge: 3 },
{ value: "threads", label: "Threads", icon: "menu" },
{ value: "you", label: "You", icon: "gear" },
];
</script>
<BottomNav {tabs} bind:value={section} label="Sections" />
---
import BottomNav from "@xtyle/astro/BottomNav.astro";
---
<BottomNav
value="inbox"
label="Sections"
tabs={[
{ value: "inbox", label: "Inbox", icon: "folder", badge: 3 },
{ value: "threads", label: "Threads", icon: "menu" },
{ value: "you", label: "You", icon: "gear" },
]}
/>