Secondary navigation

Use secondary navigation when a section needs side or top navigation for its pages.

Live demo

Readers use secondary navigation to move within a unit, faculty, or subsection without going back to the global menu. Content authors pick a root page in the tree and how deep the menu should go; page titles (or navigation titles) become link labels. Vertical layouts suit sidebars; horizontal layouts suit section bars, with dropdowns on large screens and expandable behaviour on small screens.

Behaviour

The menu reflects the AEM page tree under the chosen root, not a hand-picked list of arbitrary URLs. Pages marked hide in navigation are usually skipped, except where the implementation treats the root level specially when display root is enabled.

Vertical mode shows nested levels; people can expand and collapse branches to scan long structures. Horizontal mode shows top-level items in a row; child pages appear in dropdown panels on wide viewports, and a compact pattern (for example arrow toggles) on narrow viewports.

The current page is highlighted so people know where they are. If the tree yields no usable links, the component shows an empty state instead of a broken menu.

Anatomy

Vertical

  1. Landmark region for secondary navigation.
  2. Nested lists of links by level.
  3. Expand and collapse controls for branches that have children.
  4. Current page indicated on the active item.

Horizontal

  1. Landmark region for secondary navigation.
  2. Bar aligned with standard content widths.
  3. Top-level links with dropdown areas for children where applicable.
  4. Current page indicated on the active item.

Secondary navigation (placeholder)

Replace with vertical sidebar and horizontal bar examples.

Content guidelines

  • Set navigation title on section pages when the menu label should differ from the page title (for example shorter labels in the rail).
  • Choose a root that matches how people think about the section; too shallow feels empty, too deep can overwhelm.
  • Review horizontal navigation on phones and with keyboard, because dropdowns and toggles are easy to get wrong.

When to use

  • In-section navigation when the information architecture is already reflected in the AEM page tree.
  • Vertical for sidebars and long nested lists.
  • Horizontal for section bars under the hero or global header.

When not to use

  • Arbitrary link collections not tied to the tree; use Link list or a curated pattern.
  • A single flat list of unrelated URLs; use a simpler pattern.

Best practices

Do

  • Align labels with breadcrumbs and page titles so orientation stays consistent.
  • Test horizontal dropdowns on narrow viewports and with keyboard focus on the arrow controls.

Don't

  • Rely on this component for access control; it only mirrors structure people can already reach by URL.
  • Expect permissions to change because a page is hidden from the menu; hide in nav affects discovery, not security.

Related

Resource
NavigationPrimary site navigation and global header.
Link listCurated lists of links not driven by the page tree.
BreadcrumbHierarchy trail; often complements section navigation.

Horizontal and vertical variants share the secondary navigation clientlib. Width classes align horizontal bars with 940px or 1200px content widths. Horizontal markup uses Bootstrap layout utilities (d-flex, flex-lg-row, and similar) for responsive behaviour. Vertical menus use nested levels and arrow affordances scoped to each instance.

  • Both layouts expose role="navigation" and aria-label="Secondary navigation".
  • Vertical links set aria-current="page" on the active item.
  • Horizontal sets aria-current="page" on the active anchor via script; the arrow uses tabindex="0" and keypress to mirror click behaviour.
  • Prefer visible labels for expanders; the SVG uses aria-label="Arrow" in markup.

Testing

Re-check expand and collapse, dropdown open and close, and keyboard order after template or clientlib changes.

CRXDE Lite query

Use this query in CRXDE Lite to find instances of this component.

/jcr:root/content//*[@sling:resourceType = 'concordia/components/secondary-navigation/secondary-navigation.jsp']

Technical behaviour

secondary-navigation.jsp dispatches to horizontal or vertical scripts from the horizontal checkbox.

Both modes resolve rootPath to a page; if missing or invalid, they fall back to currentPage.getParent(). They walk child pages up to a configured depth (vertical) or a fixed depth in the horizontal renderer (horizontal ignores the dialog max depth; depth is set in script). Pages with hideInNav are skipped except at the special root level when display root is used.

The current page is marked with active and aria-current="page" where applicable.

Vertical mode uses nested <ul> levels, expand and collapse buttons for branches, and delegated jQuery handlers so multiple instances on one page (for example CDS offcanvas plus sidebar) do not double-bind events.

Horizontal mode renders dropdown blocks per top-level item; on viewports under 992px, tapping the arrow toggles the submenu. Desktop layout uses flex row and optional width and bottom border classes.

If the tree yields no usable links, empty.jsp is included.

Anatomy (markup)

Vertical

  1. Wrapper: div.vertical-menu with role="navigation", aria-label="Secondary navigation", and a unique id derived from the resource path plus an instance counter.
  2. Lists: Nested ul.level0, ul.level1, … with inline display for initial open or closed state.
  3. Items: li with li.open on the ancestor path; div.vertical-nav-item with a (and optional button.arrow for expand and collapse).

Horizontal

  1. Wrapper: div.secondary-nav-horizontal with role="navigation" and aria-label="Secondary navigation".
  2. Inner: div.mx-auto with width class (width940 or width1200), optional with-root, optional with-border.
  3. Dropdowns: div.secondary-nav-dropdown with link, optional span.arrow (keyboard focusable), and div.secondary-nav-dropdown-content for children.

Authoring

Field Applies to Purpose
Root path Both Path field; start of the tree (defaults to parent).
Display root Both When true, include the root page as its own level (vertical: -1 level logic; horizontal: with-root and deeper recursion).
Max depth Vertical only Number field 1–3; depth of child levels.
Horizontal Both Checkbox; if true, horizontal.jsp is used. Horizontal ignores max depth from the dialog (fixed depth in script).
Width (links) Horizontal width940 or width1200 on the inner container.
Border bottom Horizontal Adds with-border when true.

Instances in the codebase

Script Role
secondary-navigation.jsp Dispatches to horizontal or vertical.
vertical.jsp Recursive tree, expanders, instance-scoped id.
horizontal.jsp Dropdown bar, mobile toggle script, NavigationRenderer with max depth 2 or 3 depending on display root.
empty.jsp Shown when no links render.
Item Location
Entry apps/concordia/components/secondary-navigation/secondary-navigation.jsp
Vertical apps/concordia/components/secondary-navigation/vertical.jsp
Horizontal apps/concordia/components/secondary-navigation/horizontal.jsp
Dialog apps/concordia/components/secondary-navigation/dialog.xml

Scripts: Horizontal jQuery runs on load (dropdown toggle, aria-current on .active). Vertical uses delegated click on .vertical-menu button.arrow and a one-time window.secondaryNavVerticalBound guard, plus secondaryNavigationInit per instance (defined in shared clientlibs).