sidebar
The Sidebar component provides a vertical navigation menu with support for nested links, expandable groups, optional footer content, and consumer-controlled active state matching.
Usage
Default
const links = [
{ label: "Dashboard", href: "/dashboard", icon: <FaBook /> },
{
label: "Reports",
href: "/reports",
children: [
{ label: "Monthly", href: "/reports/monthly", icon: <FaCalendar /> },
{ label: "Annual", href: "/reports/annual", icon: <FaCalendar /> },
],
icon: <FaPaperclip />,
},
{ label: "Settings", href: "/settings", icon: <FaCogs /> },
];
const currentPath = "/settings";
const normalizePath = (p: string) =>
p.endsWith("/") && p.length > 1 ? p.slice(0, -1) : p;
const isDescendantPath = (parentPath: string, currentPath: string) => {
const parent = normalizePath(parentPath);
const current = normalizePath(currentPath);
if (parent === "/") return current === "/";
return current === parent || current.startsWith(`${parent}/`);
};
const isActiveRecursive = (link, matcher) => {
if (matcher(link)) return true;
return !!link.children?.some((child) => isActiveRecursive(child, matcher));
};
const isLinkActive = (link) => {
if (!link.href) return false;
if (link.children?.length) {
return isDescendantPath(link.href, currentPath);
}
return normalizePath(link.href) === normalizePath(currentPath);
};
const hasActiveChild = (link) =>
!!link.children?.some((child) => isActiveRecursive(child, isLinkActive));
<Sidebar
links={links}
isLinkActive={isLinkActive}
hasActiveChild={hasActiveChild}
/>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| links | Array<{ label: string; href?: string; icon?: ReactNode; children?: SidebarLink[] }> | - | Array of navigation links. Each link can include a label, optional href, optional icon, and optional nested children. |
| isLinkActive | (link: SidebarLink) => boolean | - | Optional callback used to determine whether a link should be styled as active. This allows the consumer app to fully control active route matching. |
| hasActiveChild | (link: SidebarLink) => boolean | - | Optional callback used to determine whether a link contains an active child. Useful for opening and highlighting parent sections based on app-specific routing rules. |
| theme | "primary" | "secondary" | "tertiary" | "quaternary" | "clear" | Configured Default | Theme color for the sidebar. |
| state | "success" | "error" | "warning" | - | Visual state for feedback, such as success, warning, or error. |
| outline | boolean | false | Whether the sidebar should use an outlined style. |
| rounding | "none" | "small" | "medium" | "large" | Configured Default | Corner rounding style for the sidebar container. |
| shadow | "none" | "light" | "medium" | "strong" | "intense" | Configured Default | Box shadow style for the sidebar container. |
| showFooter | boolean | false | Whether to display the footer section at the bottom. |
| footerLinks | Array<{ label: string; href: string; icon?: ReactNode }> | - | Array of footer links displayed when `showFooter` is true. |
| footerVersion | string | - | Version label displayed in the footer, such as `v1.0.0`. |
| className | string | - | Custom class names for the sidebar wrapper. |
| ariaLabel | string | "Sidebar navigation" | ARIA label for the sidebar navigation landmark. |
| data-testid | string | "sidebar" | Test id for querying the component in tests. |