Accessibility issue with FixedHeader in data tables containing links

Accessibility issue with FixedHeader in data tables containing links

pawczapawcza Posts: 5Questions: 1Answers: 0

Link to test case: https://live.datatables.net/qacedomo/1
Debugger code (debug.datatables.net): N/A
Error messages shown: N/A
Description of problem:

I have a data table that contains links. We are trying to get the data table compliant with the following WCAG 2.2 rule: 2.4.11 Focus Not Obscured (https://www.w3.org/WAI/standards-guidelines/wcag/new-in-22/#2411-focus-not-obscured-minimum-aa ). What is happening in the test case above is temporary obstruction of the rows when tabbing backward with the keyboard.

To reproduce the issue using the test case above, tab through the data table until you reach the bottom row and then tab backwards. Notice that as you tab backwards, rows you tab to are temporarily hidden behind the Fixed Header - this makes our data table implementation not compliant with the above WCAG 2.2 rule.

Does anyone have an idea on how to improve the accessibility of this data table? One idea I have is to use JavaScript to detect the position of the element user is tabbing to and then automatically scroll user to a position that they can fully see the row, but wanted to see if other people had other ideas or maybe already have a working solution to this issue.

Note: what I also noticed is that behavior in Firefox is different than in Chrome, but in both browsers rows temporarily are obstructed by FixedHeader during tabbing backwards.

Thanks in advance for any help on this.

This question has an accepted answers - jump to answer

Answers

  • allanallan Posts: 63,489Questions: 1Answers: 10,470 Site admin
    Answer ✓

    I think you are right - a Javascript focus event handler on all elements in the table would be needed for this. Get the position of the currently focused element, see if it is under the fixed header or not, and reposition the scrolling of the page to make it visible.

    It would be quite possible. I'd welcome a pull request from yourself or anyone else who is able to work on this.

    Allan

  • pawczapawcza Posts: 5Questions: 1Answers: 0

    allan,

    Thanks for the answer. I'll see if I can work on this when I get a chance.

    Wondering if anyone else has some ideas?

  • pawczapawcza Posts: 5Questions: 1Answers: 0

    I have worked a bit on a solution. The first draft I have is below. This code will scroll user up 100 pixels when the position of the tabbed a tag is within 70 pixels from the top.

    //helper method to determine position of the element relative to view
    function getViewportPosition(element) {
    const rect = element.getBoundingClientRect();

                return {
                    left: rect.left,
                    top: rect.top
                };
            }
    
            //helper method to determine position of the element relative to page
            function getPagePosition(element) {
                const rect = element.getBoundingClientRect();
                return {
                    left: rect.left + window.scrollX,
                    top: rect.top + window.scrollY
                };
            }
    
            //add focus event listener that will make sure rows in datatable are not temporarily obstructed by the fixed header when user tabs backward through links in the table rows 
            document.addEventListener("focus", (e) => {
                //console.log(e.target.nodeName + " (" + e.target.name + ") has focus");
                //console.log(getViewportPosition(e.target).top);
    
                if(e.target.nodeName === 'A' && getViewportPosition(e.target).top < 70){
                    //scroll user up 100 pixels
                    $("html, body").animate({ 
                         scrollTop: getPagePosition(e.target).top - 100 }, 500
                     );
                }
    
            }, true);
    
  • allanallan Posts: 63,489Questions: 1Answers: 10,470 Site admin

    Nice one! Thanks for sharing that with us.

    Allan

  • pawczapawcza Posts: 5Questions: 1Answers: 0

    You bet!

  • pawczapawcza Posts: 5Questions: 1Answers: 0

    Just wanted to share our final solution. We opted out to do the following:

    • Link the following javascript file to your page:
     //add below code to drawCallbackFunc function where you change display each time the data table is redrawn
        //or to any other code where rows are added/refreshed in data table
        /*
        $(".dataTables_wrapper a").on("focus", function() {
            scrollPageUp(
                element=$(this),
                headerHeight=130
            );
            return false;
        });
        */
    
        //scroll page up if focus is on the element within headerHeight
        function scrollPageUp(element,headerHeight){
            //get position of the element on the screen as seen by the user
            $thisTrueTop = element.offset().top - $(window).scrollTop();        
            //get position of the element on the html page
            $thisDocumentTop = element.offset().top;
            //set how many pixels we will be scrolling up by
            $offsetPixels = headerHeight + 35;
    
            if($thisTrueTop < headerHeight){
                //scroll user up by offsetPixels
                $("html, body").animate({ 
                     scrollTop: $thisDocumentTop  - $offsetPixels  }, 500
                 );
            }
        }
    
    • To get the fix to actually work, you need to add the following code to the place where you initialize your data tables, in the drawCallback setting. You can adjust the headerHeight to different number, if your header is larger/smaller, just make sure to test the setting with different browser window sizes and different browsers. headerHeight is in pixels.

    Example:

    $('#myTable').DataTable({
                   "dom": "<'marginrightshow'l><'toolbar'><'alignleft marginrightshow'B><'alignleft marginrightshow'f><'clearboth'>t<'clearboth'><'clearboth'><'bottom'i><'alignleft marginrightshow'p><'pageBar'>", 
                   "fixedHeader": {
                                                                               header: true,
                                                                               footer: false
                                                                },
    ...
    drawCallback: function(settings) {
                   drawCallbackFunc(settings);
                   },
    ...
    
    

    And then add this code after the data table initialization:

    // each time the table is redrawn
    function drawCallbackFunc(settings) {       
               $(".dataTables_wrapper a").on("focus", function() {
                                scrollPageUp(
                                    element=$(this),
                                    headerHeight=130
                                );
                                return false;
               });
    }
    
    • If your datatable is dynamic with code that adds/updates rows, you’ll also need to add the listener to your code after the row is added/updated.
  • allanallan Posts: 63,489Questions: 1Answers: 10,470 Site admin

    Awesome - thank you for the follow up!

    Allan

Sign In or Register to comment.