nickdjm / accessible-menu Goto Github PK
View Code? Open in Web Editor NEWA JavaScript library to help you generate WAI-ARIA accessible menus in the DOM.
License: ISC License
A JavaScript library to help you generate WAI-ARIA accessible menus in the DOM.
License: ISC License
Technically the arrow keys, home key, and end key are all optional for disclosure menus and this should be reflected in the project.
https://www.w3.org/TR/wai-aria-practices-1.2/examples/disclosure/disclosure-navigation.html
This will 100% be a breaking change to anyone not expecting their keyboard navigation to go away, so it will need to be a v3 thing.
<button href="" class="menu-toggle"><span>☰</span><span>×</span><span class="visually-hidden"> Toggle Menu</span></button>
#main-menu > .menu-toggle span:nth-child(2) { display: none; }
#main-menu > .menu-toggle[aria-expanded="true"] span:nth-child(1) {
display: none;
}
#main-menu > .menu-toggle[aria-expanded="true"] span:nth-child(2) {
display: inline;
}
Need the following:
I noticed you recently merged browser module support into next
to help resolve issues with circular dependencies, but they are still present. There are loops between BaseMenu
/BaseMenuToggle
and validate.js
because of the isMenu()
and isMenuToggle()
implementations.
One solution could be using Symbol
to act as the unique identifier for a class. I quickly tested this idea by creating a file containing the symbols:
// _baseTypes.js
export const baseMenu = Symbol('BaseMenu');
export const baseMenuToggle = Symbol('BaseMenuToggle');
Then, adding a Symbol member to each respective class:
// _baseMenu.js
import { baseMenu } from "./_baseTypes.js";
class BaseMenu {
// ...
get [baseMenu]() {
return true;
}
}
It would then be possible to rely on the Symbol for validation rather than the class name (thus avoiding the circular import):
// validate.js
import { baseMenu } from "./_baseTypes.js";
function isMenu(element) {
// ...
if (!(element[baseMenu])) {
// ...
}
}
I realize this is probably not ideal and an extra Symbol
polyfill would be required for IE, but I wanted to at least try and provide a solution.
When you have a root menu item targeted and you hit the up/down arrows to enter the sub-menu, it moves the screen once.
The screen shouldn't move when up/down is hit on a menu item containing a submenu.
Allowing the menu to update on-the-fly based on changing props would be super useful (especially since we're using this in Vue projects quite a bit).
Things like changing hoverability or hover delay and having the menu/submenus update immediately without the need to re-initialize would not only be convenient, but also remove some strange bugs that happen with multiple events being triggered.
It would be super handy to support both multiple and no classes in the openClass/closeClass props.
This would allow for more customization (especially with utility libraries like TailwindCSS).
When you open a top-level dropdown menu and click away from it, the menu stays open.
What are the steps to reproduce this issue?
The menu should close when you click outside of it.
Right now this package will only work with JS module-based projects (anything that can import/export files).
For developers using more static development (like Drupal theming) we'll need to have a bundled version of the code that can just be included on a page and run.
Going to look into Rollup for resolve this.
Should add some basic githooks and linting.
Why is your solution better than bootstrap4 navbar?
Submenus within Menubars no longer respond to key events in Safari.
I suspect this is actually a change in Safari because I've gone back from v1.1.0 through dev and nothing works.
You should be able to enter/navigate through submenus using key bindings.
As per WAI-ARIA specifications menu toggle buttons should have an aria-controls
attributes with the ID of the menu it controls.
To implement this we'll first need to ensure all menus have IDs (we'll need to find a unique way of generating them if they don't exist), and set that in the initialization()
method of SubmenuItems.
Using the following spec: https://www.w3.org/WAI/tutorials/menus/application-menus/
We'll need to fix keybindings to match.
The only catch here would be multi-level dropdowns, through those aren't technically accessible anyways, so we may just cascade the arrow keys down...
If you're in a proper menu:
If you're in a menu with too many dropdowns
This isn't ideal, but there isn't a great way to handle people who love their mega menus.
Hi
First off: Huge thank you for this awesome package! I love how much it adds to our websites in terms of accessibility.
One thing I would like to do is bind the state of other elements to the state of a menu. For example: When a Menubar shows, I'd like to also show a backdrop obscuring everything but the menu to reduce distractions from the rest of the website; when the MenuBar hides again, I'd like to also hide the backdrop. I believe, one way to achieve such a thing would be to let MenuToggle extend EvenTarget and have it emit an Event in e.g. the open, close or toggle methods. This way, one could do something like this:
const myMenu = AccessibleMenu.Menubar({
// Options
})
myMenu.dom.controller.addEventListener('stateChange', evt => {
// do something depending on the menu's state, e.g. show or hide backdrop
})
When you're in a submenu and you hit the left/right arrows, the menu opens and focuses the first child.
The proper action to take for this would be the open the submenu, but keep focus on the root menu's menu item.
When you click an item inside of a menu, we should focus it at well so that if a user switches to a keyboard after clicking the flow isn't broken.
Hullo! So opening caveat, I'm a competent infrastructure/backend developer whose javascript and frontend are both much less polished.
That out of the way, I'm trying to use accessible-menu
to build accessible disclosure navigation menus for both a site (with multiple "books") and the books via hugo. templating.
For site navigation, this is less of an issue, but for navigation within a book, it would be extremely useful to be able to apply some automatic styling to indicate where in the book's navigation you currently are - possibly just by defaulting that section to expanded?
I've been introspecting on the initialized AccessibleMenu.DisclosureMenu
object but can't seem to figure out a way to discover the appropriate elements and toggle them. If I tab through things and introspect, I can use foo.currentMenuItem.menuElements.toggle.expand()
but I'm not sure I understand how to do this programmatically on page load.
Is this a wild anti-pattern, to pre-expand a disclosure menu to the current page? If not, I'd love to understand how to do this with accessible-menu
.
Thanks in advance (and it's okay if you don't have time/interest in answering this! 💜)
Hi,
thank you for this library!
Why do you use this in the README?
<menu>
<menu-item><a>...</a></menu-item>
In the examples you use the <nav>
and <ul>
(which make more sense to me).
I want to make sure this works with at least the latest 2 versions of most browsers.
Once we can confirm browser support, we can use this to generate something to put in the readmen.
I am looking at this html:
https://github.com/NickDJM/accessible-menu/blob/dev/test/Menubar.html
it contains a <li class="menu-item"...
very often.
Wouldn't it be nice to have it simpler?
If you compare this to this: https://jqueryui.com/menu/
The jquery-ui html code is very clean: Just <ul>
and <li>
.
It would help new users, and make the library more attractive if the basic usage works like in the jquery-ui example: without css classes.
Should provide a minified version of the accessibleMenu.js
file (along with a non-minified version).
I was reading some of the aria practices elements and I took a look at the Editor Menubar Example where it mentioned some hover functionality for menubars:
- In general, moving focus in response to mouse hover is avoided in accessible widgets; it causes unexpected context changes for keyboard users. However, like desktop menubars, there are two conditions in this example menubar where focus moves in response to hover in order to help maintain context for users who use both keyboard and mouse:
- After a parent menu item in the menubar has been activated and the user hovers over a different parent item in the menubar, focus will follow hover.
- When a submenu is open and the user hovers over an item in the submenu, focus follows hover.
It would be super cool to add this functionality to menubars (and possibly disclosure menus).
Going to need real instructions on how to use this thing.
See https://www.w3.org/TR/wai-aria-practices/examples/menubar/menubar-1/menubar-1.html
If inside of a submenu...
The right arrow should do the following:
And the left arrow should do the following:
Root-level dropdown items do not open when you hit space
. There is not event handler for them.
space
, andThe dropdown menu should open if space
is hit.
Instead of having to tab target the menu entirely and hitting enter to enter the menu, the initial time a tab lands on a menu should enter the menu to the first item.
Right now the package.json
says the entry point to the package is index.js
, which is incorrect.
It should point to src/menu.js
.
Technically there's nothing stating that tabs should function like up/down arrow keys.
We'll just remove them from the equation for a smoother flow.
There isn't really a point to force users to have to call initialize()
for everything to work.
The menu should just initialize itself once its constructed.
In MacOS, some keyboards have their Home/End keys actually bound to the Meta + Left/Right Arrows.
accessible-menu
in any browserThe Home key should select the first menu item in the menu.
The End key should select the last menu item in the menu.
The custom events add in #90 break the menu in IE because IE supports CustomEvents, but does not support constructing CustomEvents.
MDN provides a pollyfill, so we'll need to add that: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
How many nested levels are supported?
Treeview Navigation is another type of navigation mentioned in WAI-ARIA Practices. It would be cool to implement this as another type of menu that the project provides.
https://www.w3.org/TR/wai-aria-practices-1.2/examples/treeview/treeview-2/treeview-2a.html
https://www.w3.org/TR/wai-aria-practices-1.2/examples/treeview/treeview-2/treeview-2b.html
The project needs more in-depth documentation.
Stuff like basic menus, sub menus, top-level dropdown menus, what each class expects as argument, how things are validated, etc.
IE support needs babel polyfill. Need to document that.
As per WAI-ARIA specifications all menus need an aria-labelledby
property.
We can't quite do this with root menus yet, but submenus can have this implemented no problem.
We just need to make sure menu buttons have an ID and then add that to the attribute.
Since there are going to be many breaking changes and new features in v3.x it would be good to have an upgrade guide to go from v2.x to v3.x.
Some notes:
What an ID is generated through a MenuToggle
, it can lead to accessibility violations.
If the innerText
of a toggle starts with a space is it replaced with a -
, which is technically an accessibility violation. The same issue can also cause many dashes to be added to the IDs if there are spacing issues with the DOM.
Another side-effect of the current way IDs are generated is if a developer is using aria-label
instead of innerText
nothing is added to the ID string, which also causes it to start with a dash since the the string is essentially: [innerText]-[randomString]-[menu/menu-button]
.
I think the best way to go about fixing this will be to do a couple things:
innerText
, see if there's an aria-label
that can be used,-
,innerText
/aria-label
does not start or end with a -
, and[randomString]-[menu/menu-button]
You can see the dash being added here because there is no innerText
<button class="navbar-toggler" type="button" aria-expanded="false" aria-label="Toggle navigation" aria-haspopup="true" id="-qefmxrqg-menu-button" aria-controls="-qefmxrqg-menu">
<span class="navbar-toggler-icon"></span>
</button>
Here's a Bootstrap 3/Drupal example where the generated markup is causing a load of extras dashes.
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse" aria-haspopup="true" aria-expanded="false" role="button" id="-------------toggle-navigation---------------------------------------------------uikbq-menu-button" aria-controls="-------------toggle-navigation---------------------------------------------------uikbq-menu">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
Very nice! May I suggest this additional CSS that changes the sub-level indicators a bit.
nav {
justify-content: center;
}
.menu .menu-item.dropdown .menu-item > .dropdown-toggle::after {
content: "►";
margin-left: 0;
float: right;
}
@media screen and (max-width: 1069px) {
.menu .menu-item.dropdown > .dropdown-toggle::after {
margin-left: 0;
float: right;
}
.menu .menu-item.dropdown .menu-item > .dropdown-toggle::after {
content: "▼";
}
.menu .menu-item.dropdown.show > .dropdown-toggle::after {
content: "▲";
}
}
As-per WAI-ARIA specifications, when a user is inside of a menu, typing any letter from A-Z:
This isn't implemented within the current classes, so we'll need to do that.
I found some css here:
https://github.com/NickDJM/accessible-menu/blob/dev/test/css/styles.css
It would be very kind if you could provide css which works for basic usage and which does not include css for other things (like html font-family).
Roles on menu items should be:
<li role="none">
<a href="#" roles="menuitem">...</a>
</li>
They are currently:
<li role="menuitem">
<a href="#">...</a>
</li>
Just need to change the initializer for menu items to add the correct roles to both the li
and the a
elements.
Right now, there isn't a great way to handle the root menu being a dropdown menu (or submenu).
I think the best way to go about fixing this would be to change the logic of how the classes work.
Instead of having: Menu
; MenuItem
; and SubmenuItem
, we should have: Menu
; Submenu
; and MenuItem
.
This would allow us to initialize the root menu as a Submenu (Maybe rename this to DropdownMenu to make a little more sense for a root-menu).
This would be a breaking change, but also I think it would mark a good beta release point.
Hi Nick,
First of all, thanks for the great work! I'm trying to change the isHoverable
setting after initialization, depending on screen size, because my menu changes to a hamburger menu below a certain screen width. At that point I would like to disable hoverability.
I setup a DisclosureMenu
like this:
let mainMenu = new AccessibleMenu.DisclosureMenu({
menuElement: document.querySelector('ul.nav'),
menuItemSelector: '.menu-item',
menuLinkSelector: '.menu-item > a',
submenuItemSelector: '.menu-item-has-children',
submenuToggleSelector: '.menu-item-has-children > a',
submenuSelector: '.sub-menu',
openClass: 'open',
isHoverable: true,
});
And I change the isHoverable
setting to false
when the window is below a certain width (using jQuery):
$(window).on('load resize', function(){
if($(window).width() <= 860) {
mainMenu.isHoverable = false;
}
});
When I console.log the mainMenu after that, I can see that the hoverable
setting is indeed false
, but the mouseenter
and mouseleave
events are still working.
I tried to create a new DisclosureMenu
, but the events are still there from the 'old' one.
I tried to run the initialize()
method on the mainMenu
after changing isHoverable()
.
I think that there is currently no way to remove the event listeners on the submenu toggles, unless I do it manually. Or to destroy (and by that I mean destroy all event listeners) a DisclosureMenu
. I hope you understand what I'm trying to do and hopefully can point me in the right direction.
As per recommendation from David MacDonald a lot of blind users are used to using Disclosure menus instead of Menubars, so having an option (perhaps even the default option) for the Accessible Menu to be a Disclosure menu would be beneficial.
Spec of Disclosures: https://www.w3.org/TR/2019/NOTE-wai-aria-practices-1.1-20190814/#disclosure
Example of Disclosure menu: https://www.w3.org/TR/2019/NOTE-wai-aria-practices-1.1-20190814/examples/disclosure/disclosure-navigation.html
This is going to be a pretty big overhaul.
Since Babel Polyfill is deprecated, I think it would make sense for the 3 polyfills needed to just be built into the compiled minified code.
Array.from()
, Array.includes()
, and Array.find()
are all the polyfills needed for accessible-menu to work in IE11 (not sure about older versions, but 11 is all that's supported anyways).
Make rollup include the 3 polyfills needed.
I believe accessible-menu is ready for a new release, but there are a couple chores to do before hand since there have been a handful of bug fixes (particularly for 2.x).
The 1.x release is going to be very few and far between. The only reason this is getting an update is because of the Safari issue in #99 since this actually breaks all previous versions of accessible-menu.
Once all the above tasks are done a new release for 1.x an 2.x will be made.
Need at add proper validation and error handling to all classes.
Add standard-version for all the versioning and logging and whatnot.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.