Skip to content

Sidebar Nav

Sidebar Nav renders local section navigation as a labeled native navigation landmark with real nested lists and links.

Component

Use fd-sidebar-nav when a content-heavy page belongs to a broader web area and people need a consistent way to move between sibling and child pages.

When to use

  • Section navigation — use Sidebar Nav beside long-form news, policy, guidance, or resource pages.
  • Persistent local context — use it when the current page, sibling pages, and selected branch should stay consistent across a section.
  • CMS-backed navigation trees — use it when a structured tree can be passed from a route, content model, or navigation service.

When not to use

  • Do not use it for global navigation — use Global Header for primary site navigation.
  • Do not use it for in-page headings — use the Prose table-of-contents pattern for links within one page.
  • Do not use it as a menu or tree control — Sidebar Nav is site navigation, not an application command menu.
  • Do not use it to hide weak IA — if the tree is too deep or long to scan, fix the information architecture first.

Choose Nav or Menu

Use Sidebar Nav when the current page should determine which branch is visible. It renders a predictable route-driven view of the section and omits unrelated descendants from the DOM.

Use Sidebar Menu when people need to explore sibling branches without leaving the page. Sidebar Menu keeps the same local navigation treatment, but adds separate caret buttons for expanding and collapsing child branches.

Examples

Sidebar Nav renders a web-area root, a divider, top-level links, and the deterministic current branch as native links. View in Storybook →

Basic usage

html
<fd-sidebar-nav
  label="News section"
  current-href="/news-events/news/press-releases"
></fd-sidebar-nav>

<script type="module">
  const nav = document.querySelector("fd-sidebar-nav");

  nav.root = {
    label: "News & Events",
    href: "/news-events",
  };

  nav.items = [
    { id: "overview", label: "Overview", href: "/news-events" },
    {
      id: "news",
      label: "News",
      href: "/news-events/news",
      items: [
        {
          id: "global-messages",
          label: "Global Messages",
          href: "/news-events/news/global-messages",
        },
        {
          id: "press-releases",
          label: "Press Releases",
          href: "/news-events/news/press-releases",
        },
      ],
    },
  ];
</script>

Current state

  • Pass currentHref or currentId at the component level.
  • Prefer currentId when URLs can vary by environment, locale, or query string.
  • Only the matched current page link receives aria-current="page".
  • Ancestor links in the current path remain normal links. They may receive internal path styling, but they do not receive aria-current.

Visibility rule

Sidebar Nav keeps the rendered DOM small and predictable:

  • The root web-area link always renders when provided.
  • Top-level items always render.
  • Each path ancestor renders its immediate children.
  • The current item renders its immediate children when it has children.
  • A leaf-current item still shows its sibling set because those links are the selected parent’s immediate children.
  • Unrelated descendant branches are omitted from the DOM, not hidden with CSS.

Properties

NameTypeDefaultDescription
labelstring``Accessible label for the internal navigation landmark when labelledby is not provided.
labelledbystring | undefinedundefinedID of an external visible heading that labels the navigation landmark.
rootFdSidebarNavRoot | undefinedundefinedOptional level-0 web-area link rendered before the item tree.
itemsFdSidebarNavItem[][]Structured navigation tree. Invalid items without labels or hrefs are omitted.
currentHrefstring | undefinedundefinedCurrent-page href matcher. Used when currentId is not provided.
currentIdstring | undefinedundefinedCurrent-page item id matcher. Takes precedence over currentHref.
maxDepth1 | 2 | 3 | 44Maximum rendered item depth, capped to the Figma-supported four levels.
allowExplicitExpandedbooleanfalseAllows item-level expanded branches as an opt-in CMS escape hatch.
ts
type FdSidebarNavRoot = {
  label: string;
  href: string;
};

type FdSidebarNavItem = {
  id?: string;
  label: string;
  href: string;
  items?: FdSidebarNavItem[];
  expanded?: boolean;
};

CSS custom properties

NameDefaultDescription
--fd-sidebar-nav-widthvar(--fdic-layout-sidebar-width, 20rem)Inline size of the sidebar navigation.
--fd-sidebar-nav-item-min-height40pxMinimum block size for each full-row link target.
--fd-sidebar-nav-indent-stepvar(--fdic-spacing-md, 16px)Indentation step applied per item level.
--fd-sidebar-nav-current-indicator-width4pxWidth of the current-page indicator stripe.
--fd-sidebar-nav-divider-colorvar(--fdic-color-border-divider)Divider color between the root link and item tree.

Shadow parts

NameDescription
navInternal navigation landmark.
listRoot and nested unordered lists.
sublistNested unordered lists.
itemList item wrapper for each link.
linkNative full-row anchor element.
root-linkOptional level-0 web-area anchor.
dividerDivider rendered after the root link when child items are present.

Best practices

Do

  • Keep labels short and close to the destination page titles.
  • Keep ordering stable across pages in the same section.
  • Pass current state from the route or CMS, not from item-level flags.

Don’t

  • Use duplicate labels for different destinations in the same tree.
  • Use Sidebar Nav as a disclosure tree or accordion.
  • Show four levels unless the section really needs that depth.

Content guidelines

  • Use nouns people recognize, such as “Press Releases” or “Board Meetings.”
  • Avoid vague labels like “Learn more,” “Resources,” or “Other” unless that is the actual page title and surrounding context makes it clear.
  • Keep the root label to the web area or section name.
  • Review long sidebars for trust and comprehension. Users should not need to guess where a financial-service page belongs.

Accessibility

  • The component renders a native <nav> with either aria-label or aria-labelledby.
  • It renders real <ul>, <li>, and <a> elements. Links preserve right-click, copy-link, open-in-new-tab, browser status text, and normal keyboard behavior.
  • The full row is the link target.
  • Only the actual current page link receives aria-current="page".
  • V1 does not render aria-expanded because there is no disclosure control.
  • V1 does not use role="menu", menuitem, roving tabindex, or arrow-key navigation.
  • Omitted branches are absent from the DOM, so keyboard and screen reader users do not encounter hidden navigation destinations.
  • Focus remains visible in forced-colors mode.

Known limitations

  • Items are property-driven in v1. Slotted custom trees are deferred.
  • The component does not observe the router automatically. Applications must pass currentHref or currentId.
  • V1 does not provide mobile drawer behavior.
  • V1 supports up to four item levels to match the Figma indentation model.
  • allowExplicitExpanded is an escape hatch for authored CMS exceptions, not the default navigation model.
  • Sidebar Menu — use when local navigation needs user-controlled expandable branches.
  • Global Header — use for global site navigation.
  • Pagination — use for bounded result-page navigation.
  • Link — use for standalone inline or standalone navigation links.
  • Content Page Recipes — page-level layouts that can host Sidebar Nav.