Semantic-Org / Semantic-UI

Semantic is a UI component framework based around useful principles from natural language.
http://www.semantic-ui.com
MIT License
51.11k stars 4.94k forks source link

Modal component should disable keyboard navigation for hidden components #733

Open cowwoc opened 10 years ago

cowwoc commented 10 years ago

Testcase: http://jsfiddle.net/pMDsH/102/

Repro steps:

Chrome Version 33.0.1750.154 m

  1. Open http://jsfiddle.net/pMDsH/102/embedded/result/
  2. Open Developer Console
  3. Click on checkbox. Note the DOM path being logged.
  4. Click on "Add company" to trigger the modal component
  5. Click in "name". Note the DOM path being logged.
  6. Hit SHIFT-TAB. Notice that the keyboard focus is on the checkbox.
  7. Hit SPACEBAR. Notice that the checkbox gets selected/unselected in the background.

Expected behavior: When a Modal component is active, keyboard navigation should get disabled for all other components. Users should only be able to interact with modal components.

Semantic-UI already handles this for mouse clicks, but it should do the same for keyboard navigation.

jlukic commented 10 years ago

Modal clears active element focus and restores it on hide. I'd recommend using tabindex to prioritize any fields in modal. Besides this I can't see any way to handle this programmatically.

Closing until anyone has an idea for a better fix.

cowwoc commented 10 years ago

Posted http://stackoverflow.com/q/23212851/14731. Hopefully someone has an idea.

chdh commented 6 years ago

It can be done by capturing the focusin event of the document element and redirecting outside focus changes to the modal DIV element.

function startFocusJail (focusRootElement) {
   $(document).off("focusin.focusJail");
   $(document).on("focusin.focusJail", function(event) {
      if (event.target !== focusRootElement && !$.contains(focusRootElement, event.target)) {
         focusRootElement.focus();
      }
   });
}

function stopFocusJail() {
   $(document).off("focusin.focusJail");
}

startFocusJail() is called when the modal is shown and stopFocusJail() is called when the modal is hidden. The function argument focusRootElement is the modal DIV element with tabindex="-1", so that the DIV can receive the focus. A better solution would be to move the focus to the first focusable element within the DIV.

The Bootstrap modal component (_enforceFocus()) also uses this approach. Works even with IE11.

stale[bot] commented 6 years ago

There has been no activity in this thread for 90 days. While we care about every issue and we’d love to see this fixed, the core team’s time is limited so we have to focus our attention on the issues that are most pressing. Therefore, we will likely not be able to get to this one.

However, PRs for this issue will of course be accepted and welcome!

If there is no more activity in the next 90 days, this issue will be closed automatically for housekeeping. To prevent this, simply leave a reply here. Thanks!

SangeethaSanthoshKumar commented 5 years ago

Can i have any example for this? I am facing this same problem so i am trying to workout this solution but its showing error in console like Maximum call stack size exceeded.

$('#id_div').modal({
        closable: false,
        allowMultiple: true,
        context: $('#id_context'),
        onShow: function () {
           startFocusJail($('#id_div'));
        },
        onHide: function () {
           stopFocusJail();
        }
}).modal('show');
chdh commented 5 years ago

@SangeethaSanthoshKumar You have to pass a HTMLElement to startFocusJail(), not a jQuery object.

 startFocusJail($('#id_div')[0]);
lubber-de commented 3 years ago

We prepared a fix for upcoming Fomantic-UI 2.9.0 by https://github.com/fomantic/Fomantic-UI/pull/2036 We used a different approach, because the focusin solution above would always refocus the main element and did not care about tabbing order