Tab bar
A tab bar is the primary navigation for a compact app. The default bar spans the width,
with the icon above the label. af-is-fixed pins it to the bottom of the viewport,
including the safe-area inset.
This is separate from af-tabs, which switches in-page panels.
The previews below move aria-current="page" when you choose a tab, and a motion bar
also updates the indicator position.
Full width
Section titled “Full width”<nav class="af-tabbar" aria-label="Primary">
<a class="af-tabbar-item" href="#home" aria-current="page">
<span class="af-tabbar-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M4 10.5 12 4l8 6.5V20H4z"/>
</svg>
</span>
<span class="af-tabbar-label">Home</span>
</a>
<a class="af-tabbar-item" href="#search">
<span class="af-tabbar-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="6"/>
<path d="m20 20-3.5-3.5"/>
</svg>
</span>
<span class="af-tabbar-label">Search</span>
</a>
<a class="af-tabbar-item" href="#inbox">
<span class="af-tabbar-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M4 6h16v12H4z"/>
</svg>
<span class="af-dot" role="img" aria-label="New notifications"></span>
</span>
<span class="af-tabbar-label">Inbox</span>
</a>
</nav>Mark the current link with aria-current="page". A notification af-dot
sits on the icon with role="img" and an aria-label such as “New notifications”. The visible
label and the dot name are both read with the link.
Floating
Section titled “Floating”af-is-floating insets the bar, rounds it into a capsule, and shows the label only on the
current item.
<nav class="af-tabbar af-is-floating" aria-label="Primary">
<a class="af-tabbar-item" href="#home" aria-current="page">
<span class="af-tabbar-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M4 10.5 12 4l8 6.5V20H4z"/>
</svg>
</span>
<span class="af-tabbar-label">Home</span>
</a>
<a class="af-tabbar-item" href="#search">
<span class="af-tabbar-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="6"/>
<path d="m20 20-3.5-3.5"/>
</svg>
</span>
<span class="af-tabbar-label">Search</span>
</a>
<a class="af-tabbar-item" href="#inbox">
<span class="af-tabbar-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M4 6h16v12H4z"/>
</svg>
</span>
<span class="af-tabbar-label">Inbox</span>
</a>
</nav>Highlight motion
Section titled “Highlight motion”af-is-motion draws a highlight behind the current item and animates it when the custom
properties change. Measure the current .af-tabbar-item and set these on the bar:
--af-tabbar-indicator-x—offsetLeft--af-tabbar-indicator-width—offsetWidth
Include an .af-tabbar-indicator element. Without af-is-motion, the current item is
styled in place and no measurement is required. prefers-reduced-motion: reduce drops the
transition.
<nav
class="af-tabbar af-is-floating af-is-motion"
style="--af-tabbar-indicator-x: 0.35rem; --af-tabbar-indicator-width: 6.5rem;"
aria-label="Primary"
>
<span class="af-tabbar-indicator" aria-hidden="true"></span>
<a class="af-tabbar-item" href="#home" aria-current="page">
<span class="af-tabbar-label">Home</span>
</a>
<a class="af-tabbar-item" href="#search">
<span class="af-tabbar-label">Search</span>
</a>
<a class="af-tabbar-item" href="#inbox">
<span class="af-tabbar-label">Inbox</span>
</a>
</nav>