flekschas / svelte-simple-modal

A simple, small, and content-agnostic modal for Svelte v3 and v4
https://svelte.dev/repl/b95ce66b0ef34064a34afc5c0249f313
MIT License
422 stars 31 forks source link

Accessibility: keyboard focus improvements #17

Closed geoffrich closed 4 years ago

geoffrich commented 4 years ago

For modals, the WAI-ARIA Authoring Practices recommend:

  1. When the modal is opened, focus is moved to an element inside the modal (e.g. the close button)
  2. When the modal is closed, focus is returned to the element that triggered the modal
  3. Tabbing when the modal is open only focuses elements within the modal (focus trapping)

With the existing demo, when I open one of the modals I have to tab back through the page to reach the close button, which would be confusing for those who primarily navigate using the keyboard. Users of assistive technology also wouldn't know what the button did and that there's new content to interact with.

Implementing these recommendations would make the modal much more accessible to keyboard users.

flekschas commented 4 years ago

These are some excellent suggestions and I'll look into them. Meanwhile, I am happy to incorporate any PRs if you want to take a stab at implementing the behavior.

frederikhors commented 4 years ago

I think in the official Modal example code (https://svelte.dev/examples#modal) there is something for this:

const handle_keydown = e => {
  if (e.key === 'Escape') {
    close();
    return;
  }

  if (e.key === 'Tab') {
    // trap focus
    const nodes = modal.querySelectorAll('*');
    const tabbable = Array.from(nodes).filter(n => n.tabIndex >= 0);

    let index = tabbable.indexOf(document.activeElement);
    if (index === -1 && e.shiftKey) index = 0;

    index += tabbable.length + (e.shiftKey ? -1 : 1);
    index %= tabbable.length;

    tabbable[index].focus();
    e.preventDefault();
  }
};

Am I wrong?

flekschas commented 4 years ago

Yep, looks like this might work. If you need this urgently, please go set up a PR. Otherwise I'll try to add the code next time I am working on the modal.