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
- Landmark region for secondary navigation.
- Nested lists of links by level.
- Expand and collapse controls for branches that have children.
- Current page indicated on the active item.
Horizontal
- Landmark region for secondary navigation.
- Bar aligned with standard content widths.
- Top-level links with dropdown areas for children where applicable.
- Current page indicated on the active item.

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 | |
|---|---|
| Navigation | Primary site navigation and global header. |
| Link list | Curated lists of links not driven by the page tree. |
| Breadcrumb | Hierarchy 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"andaria-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 usestabindex="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
- Wrapper:
div.vertical-menuwithrole="navigation",aria-label="Secondary navigation", and a uniqueidderived from the resource path plus an instance counter. - Lists: Nested
ul.level0,ul.level1, … with inlinedisplayfor initial open or closed state. - Items:
liwithli.openon the ancestor path;div.vertical-nav-itemwitha(and optionalbutton.arrowfor expand and collapse).
Horizontal
- Wrapper:
div.secondary-nav-horizontalwithrole="navigation"andaria-label="Secondary navigation". - Inner:
div.mx-autowith width class (width940orwidth1200), optionalwith-root, optionalwith-border. - Dropdowns:
div.secondary-nav-dropdownwith link, optionalspan.arrow(keyboard focusable), anddiv.secondary-nav-dropdown-contentfor 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).