Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trap focus in html container with angular

I'm building an accessible website and trying to manage focus. I need to open a modal and then put focus on the first element in the modal then trap the focus until the modal is closed ("canceled" or "accepted").

HTML

<a href="" ng-click="modalshow = !modalshow; modal.open();">Open Modal</a>
  <div ng-show="modalshow" id="modal">
    <h3 id="tofs" >Terms of Service</h3>
    <p>Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum </p>
    <span>Cancel</span> 
    <span>Accept/span> 
  </div>
  <h2>Seprate Content</h2>

Javascript

angular.module('app')
    .controller('Controller', modalCtrl);

  function modalCtrl() {
     $scope.modal = {
       open: function() {
         angular.element('#tofs').focus();

       }
     }
  }
like image 523
im_benton Avatar asked Jul 02 '15 19:07

im_benton


People also ask

How does focus trap work?

Just like the name it's given, trap focus works by setting a trap for your subject. Once your subject moves into your trap, and your camera registers it as being in-focus, the shutter will release.

How does bootstrap modal trap focus?

Bootstrap 4: by open the first modal, the focus is a trap inside it (you can move the focus with tab key and you will never focus element outside the modal). When you open the second modal the focus is a trap inside it and again you can't focus outside element (this is right).

How do you trap a focus inside a div?

tab, shift + tab and enter key and focus should be trapped inside modal and should not go out after pressing tab key multiple times.


4 Answers

angular.element("html").on("focusin", "body", function (event) {
   if(angular.element("#modal:visible").length>0){
       event.preventDefault();
       event.stopPropagation();
       angular.element('#tofs').focus();
   }
});

you can add this code to trap all focus events to h3 tag when modal is visible.

like image 188
Asheesh Kumar Avatar answered Nov 06 '22 12:11

Asheesh Kumar


There's a directive called ngBlur, that fires an event when an element loses focus. Try executing your focus function on ng-blur

Here: https://docs.angularjs.org/api/ng/directive/ngBlur

An example: http://jsbin.com/hemaye/1/edit?html,js,output

You cannot ever select the 2nd input box because of the ng-blur statement

like image 1
siddhant Avatar answered Nov 06 '22 12:11

siddhant


There is multiple possibility to trap the focus.

One solution is to manually set tabindex="-1" temporarily on all the elements in the background of your modal when it is showed (and remove this tabindex, or revert to original tabindex when leaving modal).

Another solution is to look at how angular-bootstrap plan to fix this issue : https://github.com/angular-ui/bootstrap/issues/738

You can also look at the WAI ARIA page, they have a related content about it : http://www.w3.org/TR/wai-aria-practices/#trap_focus_div

like image 1
Jscti Avatar answered Nov 06 '22 11:11

Jscti


Okay after way too much searching, this is what I came up with. Basically I created ng-focus functions on the last element in the modal and the next element following the modal. This way I could check if the focus existed within the modal and if not, I would loop the focus back to the top.

      <a href="" ng-click="modalshow = !modalshow; modal.open();">Open Modal</a>
      <div ng-show="modalshow" id="modal">
        <h3 id="tofs" >Terms of Service</h3>
        <p>Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum </p>
        <a href="" ng-focus="modalshow.onFocus($event)">Cancel</a> 
        <a href="" ng-focus="modalshow.onFocus($event)">Accept</a> 
      </div>
      <h2>Seprate Content</h2>
      <a href="" ng-focus="modalshow.onFocus($event)">next link<a>

Javascript

angular.module('app')
    .controller('Controller', modalCtrl);

  function modalCtrl() {
     $scope.modal = {
       open: function() {
         angular.element('#tofs').focus();

       },
       onFocus: function(){
         var modal = angular.element('#modal')[0];

         if (!modal.contains( event.target ) && $scope.modalIsOpen) {
           event.stopPropagation();
           angular.element('#tofs').focus();
         }
       }
     }
  }
like image 1
im_benton Avatar answered Nov 06 '22 13:11

im_benton