Chen Yang

Highlight Nav Link for Current Page in Astro

Published on . Last updated on .

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>