Skip to content

Commit

Permalink
Add tabindexes to toolbar elements and make sure a logical tab order …
Browse files Browse the repository at this point in the history
…is maintained

This fixes the following issues:
* Make sure toolbar elements are tabbed in the correct order
* Make sure main navigation is tabbed to once the user clicks the mobile menu button

Required to maintain compliance with WCAG 2.4.3 Focus Order: (Level A).
  • Loading branch information
jadu-pulsar committed Aug 10, 2018
1 parent 79a0930 commit 8dffae3
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 11 deletions.
27 changes: 27 additions & 0 deletions js/NavMainComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var $ = require('jquery');

function NavMainComponent ($html, rootWindow) {
this.$html = $html;
this.window = rootWindow;
this.$window = $(rootWindow);
};

Expand All @@ -24,6 +25,7 @@ NavMainComponent.prototype.init = function () {
component.$body = this.$html.find('body');
component.$navMain = this.$html.find('.nav-main');
component.$contentMain = this.$html.find('.content-main');
component.$brandingLink = this.$html.find('.jadu-branding');
component.$navPrimary = this.$html.find('.nav-primary');
component.$navSecondary = this.$html.find('.nav-secondary');
component.$navTertiary = component.$navMain.find('.nav-tertiary');
Expand All @@ -36,6 +38,9 @@ NavMainComponent.prototype.init = function () {
// Calculate what primary nav items can be shown and which need to be hidden in more menu
component.adjustNavItems();

// Check which tabindexes should be applied to navigation links to ensure WCAG compliance
component.manageTabIndexes();

// Open navigation on mobile
component.$mobileMenuButton.on('click', function(event) {
var $self = $(this);
Expand All @@ -46,9 +51,13 @@ NavMainComponent.prototype.init = function () {
if ($self.text() === 'Menu') {
$self.text('Close');
$self.attr('aria-expanded', 'true');
component.$brandingLink.attr('tabindex', '3');
component.$primaryNavLinks.attr('tabindex', '3');
} else {
$self.text('Menu');
$self.attr('aria-expanded', 'false');
component.$brandingLink.attr('tabindex', '-1');
component.$primaryNavLinks.attr('tabindex', '-1');
}
});

Expand All @@ -62,6 +71,7 @@ NavMainComponent.prototype.init = function () {
// Re-adjust nav items on window resize to calc if more button is needed
component.$window.resize(function () {
component.adjustNavItems();
component.manageTabIndexes();
});

// Close navs on main content click
Expand Down Expand Up @@ -96,6 +106,23 @@ NavMainComponent.prototype.init = function () {
});
};

/**
* Unto the tabindex if the main nav is in responsive mode
* This maintains the tab order to ensure WCAG compliance
*/
NavMainComponent.prototype.manageTabIndexes = function () {
var component = this,
isMobile = !component.window.matchMedia('(min-width: 992px)').matches;

if (isMobile) {
component.$brandingLink.attr('tabindex', '-1');
component.$primaryNavLinks.attr('tabindex', '-1');
} else {
component.$brandingLink.attr('tabindex', '1');
component.$primaryNavLinks.attr('tabindex', '1');
}
};

/**
* Open secondary navigation, close all other navs and highlight primary nav item parent
* @param {jQuery} $linkClicked - jQuery object of the link clicked to open secondary nav
Expand Down
1 change: 0 additions & 1 deletion stylesheets/_component.navigation.scss
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@
margin-top: 5px;
padding: 8px 14px 6px;
text-decoration: none;

-webkit-transition: all 200ms ease-in;
transition: all 200ms ease-in;

Expand Down
36 changes: 31 additions & 5 deletions tests/js/web/NavMainComponentTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ describe('NavMainComponent', function () {
this.$window = $('<div></div>');
this.$window.height(150);
this.window = this.$window[0];
this.window.matchMedia = sinon.stub();

this.$markup = $(`
<button class="mobile-menu-button t-mobile-menu-button" aria-expanded="false" aria-controls="aria-main-nav" aria-label="Toggle main menu">Menu</button>
<nav class="nav-main" aria-label="Primary" id="aria-main-nav">
<div class="nav-primary">
<a href="http://jadu.net" class="jadu-branding">Jadu</a>
<a tabindex="1" href="http://jadu.net" class="jadu-branding">Jadu</a>
<ul class="nav-items">
<li class="nav-item">
<a href="#one" class="nav-link" aria-haspopup="true" aria-expanded="false" aria-controls="aria-secondary-nav">1</a>
Expand All @@ -41,14 +42,14 @@ describe('NavMainComponent', function () {
<div class="nav-list" data-nav="#one">
<ul class="nav-items">
<li class="nav-item">
<a href="#one_one" class="nav-link">1.1</a>
<a tabindex="1" href="#one_one" class="nav-link">1.1</a>
</li>
</ul>
</div>
<div class="nav-list" data-nav="#two">
<ul class="nav-items">
<li class="nav-item">
<a href="#two_one" class="nav-link">2.1</a>
<a tabindex="1" href="#two_one" class="nav-link">2.1</a>
</li>
</ul>
</div>
Expand All @@ -58,7 +59,7 @@ describe('NavMainComponent', function () {
<div class="nav-list">
<ul class="nav-items">
<li class="nav-item">
<a href="#three_one" class="nav-link" aria-haspopup="true" aria-expanded="false" aria-controls="aria-quaternary-nav">3.1</a>
<a tabindex="1" href="#three_one" class="nav-link" aria-haspopup="true" aria-expanded="false" aria-controls="aria-quaternary-nav">3.1</a>
</li>
</ul>
</div>
Expand All @@ -68,7 +69,7 @@ describe('NavMainComponent', function () {
<div class="nav-list" data-nav="#three_one">
<ul class="nav-items">
<li class="nav-item">
<a href="#four_one" class="nav-link">4.1</a>
<a tabindex="1" href="#four_one" class="nav-link">4.1</a>
</li>
</ul>
</div>
Expand Down Expand Up @@ -104,6 +105,10 @@ describe('NavMainComponent', function () {
this.navMainComponent = new NavMainComponent(this.$html, this.window);
});

beforeEach(function () {
this.window.matchMedia.returns({matches: true});
});

afterEach(function () {
this.$html.remove(); // Detach test DOM from the real one
delete $.fn.popover;
Expand All @@ -129,6 +134,27 @@ describe('NavMainComponent', function () {
})
});

describe('when component is initalised, the initial tabindex should remain', function () {
beforeEach(function () {
this.navMainComponent.init();
});

it('should maintain the initial tabindex', function () {
expect(this.$linkOne.attr('tabindex')).to.equal('1');
});
});

describe('when component is initalised in mobile mode, the initial tabindex should be changed to -1', function () {
beforeEach(function () {
this.window.matchMedia.returns({matches: false});
this.navMainComponent.init();
});

it('should maintain the initial tabindex', function () {
expect(this.$linkOne.attr('tabindex')).to.equal('-1');
});
});

describe('When mobile menu button is clicked', function () {
beforeEach(function () {
this.navMainComponent.init();
Expand Down
1 change: 1 addition & 0 deletions views/lexicon/includes/notifications.html.twig
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<div class="dropdown notifications">
{{
html.link({
'tabindex': '6',
'class': 'notifications-toggle is-active',
'href': '#',
'label': html.icon('bell-o', { 'label': 'Show notifications' }),
Expand Down
1 change: 1 addition & 0 deletions views/pulsar/components/nav_help.html.twig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{{
nav.help({
'tabindex': '4',
'items': [
{
'title': 'CMS',
Expand Down
7 changes: 4 additions & 3 deletions views/pulsar/layouts/base.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@

<div class="toolbar">

<button class="mobile-menu-button t-mobile-menu-button" aria-expanded="false" aria-controls="aria-main-nav" aria-label="Toggle main menu">Menu</button>
<button tabindex="2" class="mobile-menu-button t-mobile-menu-button" aria-expanded="false" aria-controls="aria-main-nav" aria-label="Toggle main menu">Menu</button>

{% block notifications %}{% endblock %}

Expand All @@ -100,6 +100,7 @@
html.button_dropdown({
'parent_class': 'dropdown user-menu btn--naked',
'label': 'Paul Stanton',
'tabindex': '5',
'items': [
html.link({
"label": html.icon('user') ~ " My details",
Expand All @@ -126,8 +127,8 @@

{% block search %}
<form action="/search" class="main-search" data-ui="search-box">
<input type="search" name="q" id="case-search" value="" placeholder="Search" title="search" class="main-search__field" autocomplete="off" aria-labelledby="search-submit">
<button id="search-submit" class="main-search__submit" type="submit" name="case-search"><i class="icon-search"><span class="hide">Search</span></i></button>
<input type="search" tabindex="3" name="q" id="case-search" value="" placeholder="Search" title="search" class="main-search__field" autocomplete="off" aria-labelledby="search-submit">
<button id="search-submit" tabindex="3" class="main-search__submit" type="submit" name="case-search"><i class="icon-search"><span class="hide">Search</span></i></button>
</form>
{% endblock %}

Expand Down
5 changes: 3 additions & 2 deletions views/pulsar/v2/helpers/nav.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<nav class="nav-main" aria-label="Primary" id="aria-main-nav">
<div class="nav-primary t-nav-primary">
<a href="{{ options.brand_link|default('#') }}" class="jadu-branding">
<a tabindex="1" href="{{ options.brand_link|default('#') }}" class="jadu-branding">
<span class="jadu-logomark"></span>
<span class="jadu-wordmark">Jadu</span>
</a>
Expand Down Expand Up @@ -120,7 +120,7 @@
)
}}
>
<a {{ attributes(options|only('href data-toggle')) }} {% if heading_id is not null %} aria-describedby="{{ heading_id }}"{% endif %} class="nav-link t-nav-link" {% if options.class is defined and 'is-active' in options.class %} aria-current="page" {% endif %} {% if options.href starts with '#' %} aria-haspopup="true" aria-expanded="false" {% if aria_controls is not null %}aria-controls="{{ aria_controls }}"{% endif %}{% endif %}>
<a tabindex="1" {{ attributes(options|only('href data-toggle')) }} {% if heading_id is not null %} aria-describedby="{{ heading_id }}"{% endif %} class="nav-link t-nav-link" {% if options.class is defined and 'is-active' in options.class %} aria-current="page" {% endif %} {% if options.href starts with '#' %} aria-haspopup="true" aria-expanded="false" {% if aria_controls is not null %}aria-controls="{{ aria_controls }}"{% endif %}{% endif %}>
{% if options.icon is defined and options.icon is not empty %}
{{ html.icon(options.icon, { 'class': 'icon-fw nav-link__icon t-nav-icon' }) }}
{% elseif options.image is defined and options.image is not empty %}
Expand Down Expand Up @@ -164,6 +164,7 @@
'href': '#',
'icon': 'question-sign',
'label': options.label|default('user guides'),
'tabindex': options.tabindex|default('0'),
'data-toggle': 'dropdown'
})
}}
Expand Down

0 comments on commit 8dffae3

Please sign in to comment.