<link rel="stylesheet" href="https://esm.sh/@erikt/ui/tab-links.css" />
Example
The overview page.
The activity page.
The settings page.
<nav class="tab-links" aria-label="Sections">
<a href="/overview" aria-current="page">Overview</a>
<a href="/activity">Activity</a>
<a href="/settings">Settings</a>
</nav>
Usage
-
Put the links directly inside
.tab-links. Use a<nav>. -
Add
aria-current="page"to the link for the current page. The highlight goes there. -
Add an
aria-labelto the<nav>if the page has more than one<nav>.
View transitions
The highlight slides to the new link during a view transition.
On the same page
Move aria-current inside
document.startViewTransition().
bar.addEventListener("click", (event) => {
const link = event.target.closest("a[href]");
if (!link || link.hasAttribute("aria-current")) return;
event.preventDefault();
document.startViewTransition(() => {
for (const a of bar.querySelectorAll("a"))
a.removeAttribute("aria-current");
link.setAttribute("aria-current", "page");
});
});
Between pages
Add this to the <head> of every page with the bar.
It must be in the <head>, or the transition
sometimes does not run.
<style>
@view-transition {
navigation: auto;
}
</style>
Change the motion
/* the highlight */
::view-transition-group(.ui-tab-links) {
animation-duration: 400ms;
animation-timing-function: var(--ease-snap);
}
/* the labels */
::view-transition-group(.ui-tab-link),
::view-transition-old(.ui-tab-link),
::view-transition-new(.ui-tab-link) {
animation-duration: 400ms;
}
Without view transitions
Add .morph if you update the bar without a view
transition, for example with htmx morphing. The highlight still
slides.
<nav class="tab-links morph">
<a href="/overview" aria-current="page">Overview</a>
<a href="/activity">Activity</a>
<a href="/settings">Settings</a>
</nav>
With icons
Put an icon before the label.
<nav class="tab-links">
<a href="/board" aria-current="page">
<svg><!-- icon --></svg> Board</a
>
<a href="/table">
<svg><!-- icon --></svg> Table</a
>
<a href="/chart">
<svg><!-- icon --></svg> Chart</a
>
</nav>
Disabled link
Add aria-disabled="true" and remove the
href.
<nav class="tab-links">
<a href="/overview" aria-current="page">Overview</a>
<a href="/analytics">Analytics</a>
<a aria-disabled="true">Reports</a>
</nav>
Several bars per page
Give each extra bar its own --ui-tab-links-name. Without
it, only one bar animates. A .morph bar does not need
a name.
<nav class="tab-links" aria-label="Folders">
<a href="/inbox" aria-current="page">Inbox</a>
<a href="/archive">Archive</a>
</nav>
<nav class="tab-links" aria-label="Sort" style="--ui-tab-links-name: ui-sort">
<a href="/inbox?sort=new">Newest</a>
<a href="/inbox?sort=old" aria-current="page">Oldest</a>
</nav>