Accessibility

The purpose of Web accessibility is to make websites accessible for people with following disabilities:

Web accessibility is also useful for people without disabilities:

Essential Web-Accessibility requirements:

Skip Links:

The main objective of skip links is to bypass long navigations in header section for example. Such links make our page more accessible for users with keyboards. Also they are helpful for quickly moving to required page sections without going through complete page.

how to implement:

Such links can be created anywhere in the page preferably on page top, usually they are invisible and made visible on focus:

Keyboard Support

Menubar
Key Function
Space / Down Arrow Opens submenu and moves focus to first item in the submenu.
Enter Activates menu item, causing the link to be activated.
Right Arrow Moves focus to the next item in the menubar.
Left Arrow Moves focus to the previous item in the menubar.
Submenu
Key Function
Enter Activates menu item, causing the link to be activated.
Escape Closes submenu and Moves focus to parent menubar item.
Right Arrow Moves focus to the next item in the submenu.
Left Arrow Moves focus to the previous item in the submenu.
Down Arrow Moves focus to the next item in the submenu.
Up Arrow
  • Moves focus to the previous item in the submenu.
  • If focus is on the first item, moves focus to parent menubar item.

Roles, States, Property and Attibutes on Elements

To add links inside the navbar, use a <ul> element with id="megaMenu" and provide role="menubar" to Identifies the element as a menubar container for a set of menuitem elements.

Then add <li> elements and provide role="none" because the parent ul is serving as a menu so the li elements are not in their required list context.

Add <a> element inside every <li> element and provide role="menuitem" to Identifies the element as a menu item. Also set Attibutes aria-haspopup="true" to identifies which menu item has submenu and aria-haspopup="false" which menu item has not submenu. And also which menu item has submenu, Adds attibutes aria-expanded="true" Indicates the submenu is in expanded state and aria-expanded="false" Indicates the submenu is in collapsed state.

Add submenu <div> after menu item and provide role="menu" to serve as submenu.

To add links inside submenu use <ul> element with role="list", inside <ul> use <li> element with role="listitem" and inside <li> use <a> element with role="menuitem".

In Mobile View, provide aria-expanded="true" to the Hamburger Toggle button, indicates the Navbar is Expanded and provide aria-expanded="false" indicates the Navbar is Collapsed.

Focus Trap

To Trap Focus while Navbar is Expanded in Mobile View, Provide aria-hidden="true" to each element (Skip Link Button, Main and Footer) on the website except the Navbar element (Header), when it is in expanded state and remove the aria-hidden attribute when it is in collapsed state and Also use Javascript Focus Function to shift focus to the Navbar Brand from the Last Navbar Item.

        <header>

          <div id="mainNavigation" class="fds--navbar">

            <div class="fds--navbar--brand">

              <a href="#" class="fds--brand--link">

                <img src="./../../images/Logo.png" alt="MobileLIVE Site Logo">

              </a>

            </div>

            <button id="navOpenerBtn" class="fds--nav--opener" aria-label="Open Navigation Menu" aria-expanded="false" onclick="openNav()"></button>

            <nav class="fds--nav" aria-label="Main Navigation">

              <ul id="megaMenu" role="menubar" class="fds--main--nav">

                <li id="home" class="fds--has--drop fds--main--nav--item" role="none">

                  <a href="#" role="menuitem" aria-haspopup="true" aria-expanded="false">Home <i class="icon-arrow-down"></i></a>

                  <button class="down-arrow" aria-label="Click here to open sub menu" aria-expanded="false">

                    <i class="icon-arrow-down"></i>

                  </button>

                  <div class="fds--droplet" role="menu">

                    <div class="fds--droplet--holder">

                      <div role="group" aria-labelledby="headingA1" class="fds--droplet--col">

                        <strong id="headingA1">Heading 1</strong>

                        <ul role="list">

                          <li role="listitem"><a href="#" role="menuitem">Item 1</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 2</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 3</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 4</a></li>

                        </ul>

                      </div>

                      <div role="group" aria-labelledby="headingA2" class="fds--droplet--col">

                        <strong id="headingA2">Heading 2</strong>

                        <ul role="list">

                          <li role="listitem"><a href="#" role="menuitem">Item 1</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 2</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 3</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 4</a></li>

                        </ul>

                      </div>

                      <div role="group" aria-labelledby="headingA3" class="fds--droplet--col">

                        <strong id="headingA3">Heading 3</strong>

                        <ul role="list">

                          <li role="listitem"><a href="#" role="menuitem">Item 1</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 2</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 3</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 4</a></li>

                        </ul>

                      </div>

                    </div>

                  </div>

                </li>

                <li id="about" class="fds--has--drop fds--main--nav--item" role="none">

                  <a href="#" role="menuitem" aria-haspopup="true" aria-expanded="false">About <i class="icon-arrow-down"></i></a>

                  <button class="down-arrow" aria-label="Click here to open sub menu" aria-expanded="false">

                    <i class="icon-arrow-down"></i>

                  </button>

                  <div class="fds--droplet" role="menu">

                    <div class="fds--droplet--holder">

                      <div role="group" aria-labelledby="headingB1" class="fds--droplet--col">

                        <strong id="headingB1">Heading 1</strong>

                        <ul role="list">

                          <li role="listitem"><a href="#" role="menuitem">Item 1</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 2</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 3</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 4</a></li>

                        </ul>

                      </div>

                      <div role="group" aria-labelledby="headingB2" class="fds--droplet--col">

                        <strong id="headingB2">Heading 2</strong>

                        <ul role="list">

                          <li role="listitem"><a href="#" role="menuitem">Item 1</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 2</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 3</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 4</a></li>

                        </ul>

                      </div>

                      <div role="group" aria-labelledby="headingB3" class="fds--droplet--col">

                        <strong id="headingB3">Heading 3</strong>

                        <ul role="list">

                          <li role="listitem"><a href="#" role="menuitem">Item 1</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 2</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 3</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 4</a></li>

                        </ul>

                      </div>

                    </div>

                  </div>

                </li>

                <li id="news" class="fds--has--drop fds--main--nav--item" role="none">

                  <a href="#" role="menuitem" aria-haspopup="true" aria-expanded="false">News <i class="icon-arrow-down"></i></a>

                  <button class="down-arrow" aria-label="Click here to open sub menu" aria-expanded="false">

                    <i class="icon-arrow-down"></i>

                  </button>

                  <div class="fds--droplet" role="menu">

                    <div class="fds--droplet--holder">

                      <div role="group" aria-labelledby="headingC1" class="fds--droplet--col">

                        <strong id="headingC1">Heading 1</strong>

                        <ul role="list">

                          <li role="listitem"><a href="#" role="menuitem">Item 1</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 2</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 3</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 4</a></li>

                        </ul>

                      </div>

                      <div role="group" aria-labelledby="headingC2" class="fds--droplet--col">

                        <strong id="headingC2">Heading 2</strong>

                        <ul role="list">

                          <li role="listitem"><a href="#" role="menuitem">Item 1</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 2</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 3</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 4</a></li>

                        </ul>

                      </div>

                      <div role="group" aria-labelledby="headingC3" class="fds--droplet--col">

                        <strong id="headingC3">Heading 3</strong>

                        <ul role="list">

                          <li role="listitem"><a href="#" role="menuitem">Item 1</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 2</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 3</a></li>

                          <li role="listitem"><a href="#" role="menuitem">Item 4</a></li>

                        </ul>

                      </div>

                    </div>

                  </div>

                </li>

                <li id="contact" class="fds--main--nav--item" role="none">

                  <a href="#" role="menuitem" aria-haspopup="false">Contact</a>

                </li>

                <li id="sitemap" class="fds--main--nav--item" role="none">

                  <a id="lastNavItem" href="#" role="menuitem" aria-haspopup="false">Sitemap</a>

                </li>

              </ul>

            </nav>

          </div>

        </header>

Within _navbar.scss, you can change the Navbar styling you want to use.

Add JQuery <script> into <head> before all other javascript to load.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>

     <script>

      var isNavOpen = false;

      var windowSize = $(window).width();

      window.addEventListener('resize', getWindowSize);


      function getWindowSize() {

        windowSize = $(window).width();

      }

      function getBreakpointValue(name){

        let value = getComputedStyle(document.documentElement).getPropertyValue(name);

        return parseInt(value,10);

      }

      document

        .getElementById('lastNavItem')

        .addEventListener('keydown', focusTrap);


      function focusTrap(e) {

        if(isNavOpen === true && e.which === 9){

          if($(window).width() < getBreakpointValue('--breakpoint-lg')){

            e.preventDefault();

            $('.fds--brand--link').focus();

          }

        }

      }


      function initMegaMenu() {

        var megaMenu = document.getElementById('megaMenu');


        // keyboard stuff

        $(megaMenu).delegate('li a', 'keydown', keyboardHandler);


        // mouse stuff

        $(' > li.fds--has--drop', megaMenu).each(function () {

          var dropdown = $('.fds--droplet', $(this)[0]);

          $(this).hover(

            function () {

              if (windowSize >= getBreakpointValue('--breakpoint-lg')){

                $(this).addClass('active');

                $(this).children('a').attr('aria-expanded', 'true');

                $('.fds--droplet', megaMenu).each(function (index, drop) {

                  if (drop !== dropdown) {

                    $(drop).hide();

                  }

                });

                $(dropdown).attr("aria-hidden", "false");

                $(dropdown).slideDown(0);

              } 

            },

            function () {

              if (windowSize >= getBreakpointValue('--breakpoint-lg')){

                $(this).removeClass('active');

                $(this).children('a').attr('aria-expanded', 'false');

                $(dropdown).slideUp(0);

              }

            }

          );

        });

      }


      function openNav() {

        var x = document.getElementById('mainNavigation');

        var y = document.getElementById('navOpenerBtn');

        var classes = x.className.split(' ');

        var i = classes.indexOf('open');


        if (i >= 0) {

          x.classList.remove('open');

          y.setAttribute('aria-label', 'Open Navigation Menu');

          y.setAttribute('aria-expanded', 'false');

          isNavOpen = false;

          document

            .getElementById('skipNavBTN')

            .setAttribute('aria-hidden', false);

          document.getElementById('main').setAttribute('aria-hidden', false);

          document.getElementById('footer').setAttribute('aria-hidden', false);

        } else {

          x.classList.add('open');

          y.setAttribute('aria-label', 'Close Navigation Menu');

          y.setAttribute('aria-expanded', 'true');

          isNavOpen = true;

          document

            .getElementById('skipNavBTN')

            .setAttribute('aria-hidden', true);

          document.getElementById('main').setAttribute('aria-hidden', true);

          document.getElementById('footer').setAttribute('aria-hidden', true);

        }

      }


      $('.down-arrow').on('click', function () {

          var parent_id = $(this).parent().attr('id');

          var x = document.getElementById(parent_id);

          var y = $(this);

          var li_has_class = x.classList.contains('active');

          const childrens = document.querySelectorAll('.fds--has--drop');

          childrens.forEach(function (elem) {

            elem.classList.remove('active');

            let caretBtn = elem.querySelector('.down-arrow');

            let label = caretBtn.getAttribute('aria-label');

            let updateLabel = label.replace('close', 'open');

            caretBtn.setAttribute('aria-label', updateLabel);

            caretBtn.setAttribute('aria-expanded', false);

          });

          if (!li_has_class) {

            x.classList.add('active');

            let caretBtn = x.querySelector('.down-arrow');

            let label = caretBtn.getAttribute('aria-label');

            let updateLabel = label.replace('open', 'close');

            caretBtn.setAttribute('aria-label', updateLabel);

            caretBtn.setAttribute('aria-expanded', true);

          }

      });


      function setAttributes(el, attrs) {

        for (var key in attrs) {

          el.querySelector('.down-arrow').setAttribute(key, attrs[key]);

        }

      }


      function keyboardHandler(keyVent) {

        var target = keyVent.target;

        var which = keyVent.which;

        if (which === 39) {

          // RIGHT

          if (isTopLevel(target)) {

            // top level item

            var nextTopItem = adjacentTopLevelItem(target, 'next');


            if (nextTopItem) {

              keyVent.preventDefault();

              nextTopItem.focus();

            }

          } else {

            // dropdown item

            var nextDropletItem = adjacentDropdownItem(target, 'next');

            if (nextDropletItem) {

              keyVent.preventDefault();

              nextDropletItem.focus();

            }

          }

        } else if (which === 37) {

          // LEFT

          if (isTopLevel(target)) {

            // top level item

            var prevTopItem = adjacentTopLevelItem(target, 'prev');


            if (prevTopItem) {

              keyVent.preventDefault();

              prevTopItem.focus();

            }

          } else {

            // dropdown item

            var prevDropItem = adjacentDropdownItem(target, 'prev');

            if (prevDropItem) {

              keyVent.preventDefault();

              prevDropItem.focus();

            }

          }

        } else if (which === 40) {

          // DOWN

          if (isTopLevel(target) && hasDropdown(target)) {

            // top level item w/ dropdown -- open dropdown

            openDropdown(target);

          } else {

            // dropdown item

            var nextDropItem = adjacentDropdownItem(target, 'next');


            if (nextDropItem) {

              keyVent.preventDefault();

              nextDropItem.focus();

            }

          }

        } else if (which === 38) {

          // UP

          if (!isTopLevel(target)) {

            if (isFirstDropItem(target)) {

              keyVent.preventDefault();

              var top = closeDropdown(target);

              setTimeout(function () {

                top.focus();

              }, 0);

            } else {

              var prevDropAnchor = adjacentDropdownItem(target, 'prev');


              if (prevDropAnchor) {

                keyVent.preventDefault();

                prevDropAnchor.focus();

              }

            }

          }

        } else if (which === 27) {

          // ESCAPE

          if (!isTopLevel(target)) {

            var topper = closeDropdown(target);

            setTimeout(function () {

              topper.focus();

            }, 0);

          }

        } else if (which === 9 && keyVent.shiftKey) {

          // SHIFT + TAB

          if (!isTopLevel(target) && isFirstDropItem(target)) {

            keyVent.preventDefault();

            var topA = closeDropdown(target);

            setTimeout(function () {

              topA.focus();

            }, 0);

          }

        } else if (which === 9) {

          // TAB

          if (!isTopLevel(target) && isLastDropItem(target)) {

            keyVent.preventDefault();

            var topItem = closeDropdown(target);

            var nextLi = $(topItem.parentNode).next()[0];

            var nextAnchor = $('a', nextLi)[0];

            nextAnchor.focus();

          }

        } else if (which === 32) {

          if (

            isTopLevel(target) &&

            $(target.parentNode).hasClass('fds--has--drop')

          ) {

            openDropdown(target);

          }

        }

      }


      // determines if the item is a top-level one

      function isTopLevel(item) {

        return $(item).is('#megaMenu > li > a');

      }


      // determines if the item has a dropdown

      function hasDropdown(item) {

        return $(item.parentNode).hasClass('fds--has--drop');

      }


      // determines if the item is the first in the dropdown

      function isFirstDropItem(item) {

        var drop = $(item).closest('.fds--droplet')[0];

        var firstInDrop = $('li a', drop)[0];


        return firstInDrop === item;

      }


      // determines if the item is the last in the dropdown

      function isLastDropItem(item) {

        var drop = $(item).closest('.fds--droplet')[0];

        var lastInDrop = $('li a', drop).last()[0];


        return lastInDrop === item;

      }


      // finds the adjacent top level item

      function adjacentTopLevelItem(item, dir) {

        var li = item.parentNode; // <li />

        var adjacentLi = dir === 'next' ? $(li).next()[0] : $(li).prev()[0];

        var adjacentItem = adjacentLi && $('a', adjacentLi)[0];


        return adjacentItem;

      }


      // finds the next or prev dropdown item

      function adjacentDropdownItem(item, dir) {

        var adjacentDropItem;

        var li = item.parentNode;

        var adjacentSameCol =

          dir === 'next' ? $(li).next()[0] : $(li).prev()[0];

        if (adjacentSameCol) {

          // there is one in the same col

          adjacentDropItem = $('a', adjacentSameCol)[0];

        } else {

          // lets look for one in the adjacent column

          var col = $(li).closest('.fds--droplet--col')[0];

          var adjacentCol =

            dir === 'next' ? $(col).next()[0] : $(col).prev()[0];

          if (adjacentCol) {

            // we've found the adjacent column

            var adjacentItem =

              dir === 'next'

                ? $('li a', adjacentCol)[0]

                : $('li a', adjacentCol).last()[0];


            if (adjacentItem) {

              adjacentDropItem = adjacentItem;

            }

          }

        }


        return adjacentDropItem;

      }


      function openDropdown(item) {

        $(item.parentNode).addClass('active');

        $(item).attr('aria-expanded', 'true');

        var caret = $(item).next()[0];

        var droplet = $(caret).next()[0];

        $(droplet).attr('aria-hidden', 'false');

        // open the dropdown...

        $(droplet).slideDown(100);

        // ...and focus the first item

        setTimeout(function () {

          $('a', droplet)[0].focus();

        }, 100);

      }


      function closeDropdown(item) {

        var droplet = $(item).closest('.fds--droplet')[0];

        $(droplet).attr('aria-hidden', 'true');

        var caret = $(droplet).prev()[0];

        var topLevelItem = $(caret).prev()[0];

        $(topLevelItem).attr('aria-expanded', 'false');

        $(topLevelItem.parentNode).removeClass('active');

        $(droplet).slideUp(100);


        return topLevelItem;

      }


      ////////////////////////////////////

      $(document).ready(initMegaMenu);

      ////////////////////////////////////

      //

    </script>