npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@wanjapflueger/a11y-menu

v2.5.2

Published

A fully accessible menu

Downloads

24

Readme

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.

| Name | Required | Type | Default value | Description | Example | | -------------------------------------------- | -------- | ------------------- | ------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | nav | ✅ Yes | HTMLElement | | Navigation element. Any HTMLElement being a <nav> element. | <nav>...</nav> | | config | ❌ No | Config | undefined | Menu 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

| Key | Description | | ------------ | ------------------------------------------------- | | ArrowRight | Next or submenu (direction === 'horizontal') | | ArrowDown | Next or submenu (direction === 'vertical') | | ArrowLeft | Previous or parent (direction === 'horizontal') | | ArrowUp | Previous or parent (direction === 'vertical') |

Accessibility Compliance Report

WCAG Level: AAA [^1]

| Browser | Platform | Screen reader | Passed | | ----------------- | ------------- | ---------------------------------------------------------------------------- | ------ | | Chrome 95 | Windows 10 | NVDA | ✅ | | Firefox 93 | Windows 10 | NVDA | ✅ | | Microsoft Edge 95 | Windows 10 | NVDA | ✅ | | Chrome 94 | Android 10 | TalkBack | ✅ | | Chrome 95 | MacOS 11.15.2 | VoiceOver | ✅ | | Firefox 90 | MacOS 11.15.2 | VoiceOver | ✅ | | Microsoft Edge 95 | MacOS 11.15.2 | VoiceOver | ✅ |


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