Update in 2025
This article was first written in 2022, when Astro was very new. Now in 2025, it has evolved significantly and has a new built-in way to get the active state. The code is shown below, but I'll keep the older methods for reference.
// in the JavaScpit part:
// the `pathname` is sth like - "/about"
const { pathname } = Astro.url;
// in the HTML part:
<a class={pathname.slice(1) === 'about' ? 'active' : ''} href="/about">
About
</a>
Accessibility Practice
For better accessibility, we can enhance our navigation by using the aria-current
attribute instead of just CSS classes. While CSS classes like .active
only provide visual feedback, aria-current
can communicate the current page both visually and semantically to assistive technologies.
// in the HTML part:
<a
aria-current={pathname.slice(1) === 'about' ? 'page' : 'false'}
href="/about"
>
About
</a>
// in the CSS part:
a[aria-current="page"] {
/* the styles for the active nav item */
}
The aria-current
attribute accepts several values, but for navigation we use "page"
to indicate the current page, or "false"
for non-current pages. This provides a more semantic way to mark the active navigation item compared to CSS classes. Learn more about it on the MDN Docs.
The Old Methods
This article is about how to give the navigation items for each page in the new static site generator - Astro - an active-state style. (What a long sentence. 😮💨)
And there are two ways. (These code are written in Astro Component.)
The Old Good JavaScript Way
In the code below, we write the vanilla JavaScript in a script
tag, which tells Astro to give this code block to the browser. It will work in a regular way.
// src/components/Navbar.astro
<nav>
<a class="active" href="/">Home</a>
<a href="/portfolio">Portfolio</a>
<a href="/posts">Article</a>
<a href="/about">About Me</a>
<a href="/contact">Contact Me</a>
</nav>
<script>
const navLinks = document.querySelectorAll("nav a");
navLinks.forEach((link) => {
link.classList.remove("active");
// `slice` here to remove the first `/` in pathname
const currentPath = window.location.pathname.slice("1");
// `link.href` returns a whole url, such as: "https://somedomain.com/posts" and we only need the last part
const hrefArray = link.href.split("/");
const thisPath = hrefArray[hrefArray.length - 1];
if (currentPath === thisPath) {
link.classList.add("active");
}
});
</script>
The Astro Way
We take advantage of Astro's Runtime API and get the pathname in Astro components' component script.
// src/components/Navbar.astro
---
const pathname = new URL(Astro.request.url).pathname;
const currentPath = pathname.slice(1); // remove the first "/"
---
<nav>
<a class={currentPath === "" ? "active" : ""} href="/">Home</a>
<a class={currentPath === "portfolio" ? "active" : ""} href="/portfolio">Portfolio</a>
<a class={currentPath === "posts" ? "active" : ""} href="/posts">Article</a>
<a class={currentPath === "about" ? "active" : ""} href="/about">About Me</a>
<a class={currentPath === "contact" ? "active" : ""} href="/contact">Contact Me</a>
</nav>