UI Patterns

Expandable navigationStatusrelease

Show and hide navigation with a button.

Guidance

Use this pattern for hamburger-type navigation that expands and collapses in the document flow. The expandable navigation pattern remains open when the focus moves out of the navigation and allows interaction with the rest of the page while it is open.

Example

Open in a new tab

Dependencies and installation

PackageInstallation
@stormid/toggle
npm i -S @stormid/toggle

Code

<nav class="expandable-nav__nav" aria-label="Primary navigation"><button type="button" class="expandable-nav__btn js-expandable-nav__toggle" aria-label="Show navigation menu" aria-controls="expandable-nav" aria-expanded="false" data-show-label="Show navigation menu" data-hide-label="Hide navigation menu"><svg focusable="false" class="expandable-nav__btn-icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path></svg>menu</button><div id="expandable-nav" class="expandable-nav__display-wrap js-expandable-nav" data-toggle="js-expandable-nav__toggle"><ul class="expandable-nav__list"><li class="expandable-nav__item"><a class="expandable-nav__link" href="#">Item 1</a></li><li class="expandable-nav__item"><a class="expandable-nav__link is--active" href="#" aria-current="page">Item 2</a></li><li class="expandable-nav__item"><a class="expandable-nav__link" href="#">Item 3</a></li><li class="expandable-nav__item"><a class="expandable-nav__link" href="#">Item 4</a></li><li class="expandable-nav__item"><a class="expandable-nav__link" href="#">Item 5</a></li></ul></div></nav>
import toggle from '@stormid/toggle';

const toggleInstances = toggle('.js-expandable-nav', { focus: false });

//to change the aria-label when navigation is toggled
const SHOW_LABEL_ATTRIBUTE = 'data-show-label';
const HIDE_LABEL_ATTRIBUTE = 'data-hide-label';
const toggleAriaLabel = e => {
    const { toggles } = e.detail.getState();
    toggles.forEach(btn => {
        if (!btn.hasAttribute(SHOW_LABEL_ATTRIBUTE) && !!btn.hasAttribute(SHOW_LABEL_ATTRIBUTE)) return;
        btn.setAttribute('aria-label', (btn.getAttribute('aria-expanded') === 'true') ? btn.getAttribute(HIDE_LABEL_ATTRIBUTE) : btn.getAttribute(SHOW_LABEL_ATTRIBUTE));
    });
};
toggleInstances.forEach(instance => {
    instance.getState().node.addEventListener('toggle.open', toggleAriaLabel);
    instance.getState().node.addEventListener('toggle.close', toggleAriaLabel);
});

Acceptance criteria

The following is a list of example acceptance criteria to test against when using this pattern. These critera should test that the specific markup requirements are met, and that the navigation behaves visually and functionally as expected.

For validation in developer tools / web inspector

For visual validation

For functional validation

References