Sidebar Links
Understanding the sidebar accordion links
Last updated: July 1, 2025
The SidebarLinks
component handles the navigation structure for each section in the docs sidebar, with collapsible accordion functionality and active state highlighting.
Usage
Each section (e.g. “Getting Started”, “Components”, etc.) is passed to this component via props:
interface Props {
title: string;
docs: Array<{ slug: string; title: string; order: number }>;
index: number;
}
It expects a list of docs
belonging to that category, and renders them under a toggleable section.
Accordion Behavior
Each section is collapsed or expanded based on the current page. This logic is handled by:
const isOpenByDefault =
docs.some((doc) => currentPath === `/docs/${doc.slug}` || currentPath === `/docs/${doc.slug}/`) ||
(title.toLowerCase() === "integrations" && currentPath.startsWith("/integrations")) ||
(title.toLowerCase() === "changelog" && currentPath.startsWith("/changelog"));
This ensures:
- The accordion automatically opens if the current route matches one of its links
- The background highlight fades in when open
Highlight Background
A subtle background overlay appears when a section is open. It’s handled by this block:
<div
class="absolute inset-y-0 left-0 right-0 bg-base-50 dark:bg-white/2 rounded-md transition-all duration-300 z-0"
data-background
aria-hidden="true"
></div>
This layer is placed behind the content using z-0
so the button and nav remain clickable.
Toggle Button
The section header is rendered as a styled button:
<button
class="relative w-full px-4 py-2.5 text-left text-xs font-medium text-base-900 dark:text-white z-10"
data-accordion-trigger
aria-expanded={isOpenByDefault}
>
{title}
</button>
This button toggles the visibility of the section’s links and updates aria-expanded
.
Content Area
The links are wrapped inside a div.accordion-content
, which is animated using height
, opacity
, and transform
:
<div
class="overflow-hidden accordion-content transition-all duration-500 ease-in-out"
style={`height: ${isOpenByDefault ? "auto" : "0"}; opacity: ${isOpenByDefault ? "1" : "0"}; transform: translateY(${isOpenByDefault ? "0" : "-0.5rem"})`}
>
<nav> ... </nav>
</div>
JavaScript handles toggling these styles smoothly.
Link Highlighting
Each link uses active state styling if the current path matches:
const isActive = currentPath === href || currentPath === `${href}/`;
Links get a colored left border and updated text color when active:
<a
class={`block px-3 ml-4 py-2 text-xs border-l ${
isActive
? "border-l-accent-500 dark:border-l-accent-400 text-base-600 font-medium"
: "border-l-base-300 dark:border-l-base-500 text-base-500 hover:text-base-600"
}`}
>
{doc.title}
</a>
JavaScript Interactivity
Accordion toggling is powered by a small script:
document.addEventListener("astro:page-load", initializeAccordions);
document.addEventListener("DOMContentLoaded", initializeAccordions);
function initializeAccordions() {
const sections = document.querySelectorAll(".accordion-section");
sections.forEach((section) => {
const toggle = section.querySelector("[data-accordion-trigger]");
const content = section.querySelector(".accordion-content");
const background = section.querySelector("[data-background]");
toggle?.addEventListener("click", () => {
const isOpen = toggle.getAttribute("aria-expanded") === "true";
sections.forEach((s) => {
// collapse others
});
// toggle current
if (isOpen) {
...
} else {
...
}
});
});
}
This ensures:
- Only one section is open at a time
- Animations apply smoothly
aria-expanded
reflects state
Accessibility Notes
- Uses semantic
<button>
for toggling - Manages
aria-expanded
attributes - Keyboard and screen reader friendly
Customization
You can:
- Change the section background (
data-background
) - Override transitions via Tailwind utilities
- Customize the
SidebarLinks.astro
to remove the JS and use native<details>
if desired
Troubleshooting
- Accordion not clickable? Check
z-index
anddata-background
isn’t covering the button - Not toggling? Ensure JS runs on
astro:page-load
andDOMContentLoaded
- Wrong links opening? Ensure
slug
values in frontmatter match sidebar structure
Example
<SidebarLinks
title="Components"
docs={[
{ slug: "button", title: "Button", order: 1 },
{ slug: "badge", title: "Badge", order: 2 },
]}
index={1}
/>
This component powers all dynamic navigation in the sidebar and is designed to work seamlessly with content collections.