2.5.2 • Published 2 years ago

@wanjapflueger/a11y-menu v2.5.2

Weekly downloads
-
License
ISC
Repository
gitlab
Last release
2 years ago

a11y-menu

A menu that is fully accessible. It has no design or theme applied. That way you can be certain the menu is usable and accessible and you can apply your own styles.

Pipeline status npm npm bundle size


Table of contents


Requirements

  • You need to be able to import or require JavaScript files

Changelog

See changelog.md.

Install

npm i @wanjapflueger/a11y-menu

Example

example.barrierefrei.kiwi/a11y-menu/

Usage

Init

Import class Menu.

import { Menu } from '@wanjapflueger/a11y-menu';
// var a11yMenu = require("@wanjapflueger/a11y-menu")

Create a new instance

const myMenu = new Menu();
// const myMenu = new a11yMenu.Menu();

Methods

Method Create

  1. Create a navigation of this simple structure.

    <nav>
      <ul>
        <li><a href="/">Home</a></li>
        <li>
          <span>Topics</span>
          <ul>
            <li><a href="/dogs">Dogs</a></li>
            <li><a href="/cats">Cats</a></li>
            <li><a href="/birds">Birds</a></li>
          </ul>
        </li>
        <li><a href="/contact">Contact</a></li>
        <li><a href="/privacy">Privacy</a></li>
      </ul>
    </nav>

    Important:

    • Each HTMLLIElement including a direct child (HTMLUListElement, submenu) HTMLSpanElement.
    • It is not possible to create a link on a HTMLLIElement that includes a direct child (HTMLUListElement, submenu)

      <!-- ✅ Do -->
      <li>
        <span>Topics</span>
        <ul>
          <li><a href="/dogs">Dogs</a></li>
          <li>...</li>
        </ul>
      </li>
      
      <!-- ❌ Do not -->
      <li>
        <a href="/topics">Topics</a>
        <ul>
          <li><a href="/dogs">Dogs</a></li>
          <li>...</li>
        </ul>
      </li>
  2. Assign that navigation element with JavaScript to a variable, initiate a new instance of Menu and call method Create.

    import { Menu } from '@wanjapflueger/a11y-menu';
    
    const myMenu = new Menu();
    myMenu.Create({
      nav: document.querySelector('nav'),
    });
Parameters

See MenuParameters in src/index.ts.

NameRequiredTypeDefault valueDescriptionExample
nav✅ YesHTMLElementNavigation element. Any HTMLElement being a <nav> element.<nav>...</nav>
config❌ NoConfigundefinedMenu configuration.{ responsive: [{minWidth: 768, config: [{closeOnNavigate: true, direction: 'x', level: 0}]}] }

Config

import { Menu } from '@wanjapflueger/a11y-menu';

const myMenu = new Menu();
myMenu.Create({
  nav: document.querySelector('nav'),
  config: {
    breakpoints: [
      {
        minWidth: 0,
        config: [
          {
            closeOnNavigate: false,
            level: 0,
          },
        ],
      },
      {
        minWidth: 768,
        config: [
          {
            closeOnNavigate: false,
            closeOnClick: true,
            direction: 'vertical',
            level: 0,
          },
        ],
      },
      {
        minWidth: 1280,
        config: [
          {
            direction: 'horizontal',
            level: 0,
          },
          {
            direction: 'vertical',
            level: 1,
          },
        ],
      },
    ],
  },
});

This would mean:

  1. On screens bigger than 768px and smaller than 1280px...

    1. on MenuItem.level === 0 use the up- and down arrow keys to go to the next MenuItem
  2. On screens bigger than 1280px...

    1. On MenuItem.level === 0 use the left- and right keys to go to the next MenuItem

    2. On MenuItem.level === 1 use the up- and down keys to go to the next MenuItem

The default value for direction is always 'vertical'.

Styles

The menu does not come with any design or theme applied.

Selectors

To apply styles for different states, use these selectors:

[role='menubar'] {
  /** Top level menu */
}

[role='menu'] {
  /** Sub menus */
}

[role='none'] {
  /** Menu item parent with no function. Only when the [role='menuitem'] is an anchorlink element */
}

a[role='menuitem'] {
  /** Menu item that is clickable */
}

li[role='menuitem'] {
  /** Menu item that contains a submenu ([role="menu"]) */
}

[role='menuitem'][aria-expanded='true'] {
  /** Menu items that are expanded */
}

[role='menuitem'][data-focus='true'] {
  /** The menu item that has the focus */
}

[role='menuitem'][aria-current='page'] {
  /** Menu items that match the current page */
}

[role='menuitem'][data-current-parent='true'] {
  /** Menu items that are parents of the [aria-current="page"] */
}

[role='menuitem'][data-level='{number}'] {
  /** The depth level of a menu item (replace `{number}` with a number, starting with `0`) */
}

Example Styles

Here are some example styles.

ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
}

[role='menubar'] {
  display: flex;
}

[role='menuitem'] {
  position: relative;
  background-color: #ccc;
  min-width: 100px;
  display: block;
  cursor: pointer;
  padding: 5px 10px;
}

[role='menuitem']:hover,
[role='menuitem']:focus-visible {
  text-decoration: underline;
}

[role='menuitem'] > ul {
  position: absolute;
}

[aria-expanded='false']::before {
  content: '→';
}
[aria-expanded='true']::before {
  content: '↓';
}

[aria-expanded='false'] > ul {
  display: none;
}

nav > ul > li > ul > li ul {
  left: 100%;
  top: 0;
  outline: 1px solid red;
}

Keyboard support

In index.ts at menuItemControls several keys have been assigned a function. The keyboard support starts when any element in the menu is active. A menu is active when:

  • any nav [role="menuitem"] is focussed
KeyDescription
ArrowRightNext or submenu (direction === 'horizontal')
ArrowDownNext or submenu (direction === 'vertical')
ArrowLeftPrevious or parent (direction === 'horizontal')
ArrowUpPrevious or parent (direction === 'vertical')

Accessibility Compliance Report

WCAG Level: AAA ^1

BrowserPlatformScreen readerPassed
Chrome 95Windows 10NVDA
Firefox 93Windows 10NVDA
Microsoft Edge 95Windows 10NVDA
Chrome 94Android 10TalkBack
Chrome 95MacOS 11.15.2VoiceOver
Firefox 90MacOS 11.15.2VoiceOver
Microsoft Edge 95MacOS 11.15.2VoiceOver

^1: This information refers only to the technical aspects of the component, not to the design or the editorial handling of any content.

3.0.0

2 years ago

2.5.2

2 years ago

2.6.1

2 years ago

2.6.0

2 years ago

2.5.0

2 years ago

2.5.1

2 years ago

2.4.0

2 years ago

2.3.0

3 years ago

2.2.0

3 years ago

2.1.1

3 years ago

2.1.0

3 years ago

2.0.0

3 years ago

1.2.0

3 years ago

1.2.3

3 years ago

1.2.2

3 years ago

1.2.1

3 years ago

1.1.0

4 years ago

1.0.0

4 years ago

0.0.1

4 years ago