-
Notifications
You must be signed in to change notification settings - Fork 334
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2450 from alphagov/focus-skiplink-target
Set focus to skip link target to improve screen reader announcements
- Loading branch information
Showing
10 changed files
with
199 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,6 +53,7 @@ describe('GOV.UK Frontend', () => { | |
'ErrorSummary', | ||
'Header', | ||
'Radios', | ||
'SkipLink', | ||
'Tabs' | ||
]) | ||
}) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import '../../vendor/polyfills/Function/prototype/bind' | ||
import '../../vendor/polyfills/Element/prototype/classList' | ||
import '../../vendor/polyfills/Event' // addEventListener and event.target normalization | ||
|
||
function SkipLink ($module) { | ||
this.$module = $module | ||
} | ||
|
||
/** | ||
* Initialise the component | ||
*/ | ||
SkipLink.prototype.init = function () { | ||
var $module = this.$module | ||
// Check for module | ||
if (!$module) { | ||
return | ||
} | ||
|
||
$module.addEventListener('click', this.handleClick.bind(this)) | ||
} | ||
|
||
/** | ||
* Click event handler | ||
* | ||
* @param {MouseEvent} event - Click event | ||
*/ | ||
SkipLink.prototype.handleClick = function (event) { | ||
var target = event.target | ||
|
||
if (this.focusLinkedElement(target)) { | ||
event.preventDefault() | ||
} | ||
} | ||
|
||
/** | ||
* Focus the linked element | ||
* | ||
* @param {HTMLElement} $target - Event target | ||
* @returns {boolean} True if the linked element was able to be focussed | ||
*/ | ||
SkipLink.prototype.focusLinkedElement = function ($target) { | ||
// If the element that was clicked does not have a href, return early | ||
if ($target.href === false) { | ||
return false | ||
} | ||
|
||
var linkedElementId = this.getFragmentFromUrl($target.href) | ||
var $linkedElement = document.getElementById(linkedElementId) | ||
if (!$linkedElement) { | ||
return false | ||
} | ||
|
||
if (!$linkedElement.getAttribute('tabindex')) { | ||
// Set the content tabindex to -1 so it can be focused with JavaScript. | ||
$linkedElement.setAttribute('tabindex', '-1') | ||
$linkedElement.classList.add('govuk-skip-link-focused-element') | ||
|
||
$linkedElement.addEventListener('blur', this.removeFocusProperties.bind(this, $linkedElement)) | ||
} | ||
$linkedElement.focus() | ||
} | ||
|
||
/** | ||
* Remove the tabindex that makes the linked element focusable because the content only needs to be | ||
* focusable until it has received programmatic focus and a screen reader has announced it. | ||
* | ||
* Remove the CSS class that removes the native focus styles. | ||
* | ||
* @param {HTMLElement} $linkedElement - DOM element linked to from the skip link | ||
*/ | ||
SkipLink.prototype.removeFocusProperties = function ($linkedElement) { | ||
$linkedElement.removeAttribute('tabindex') | ||
$linkedElement.classList.remove('govuk-skip-link-focused-element') | ||
} | ||
|
||
/** | ||
* Get fragment from URL | ||
* | ||
* Extract the fragment (everything after the hash) from a URL, but not including | ||
* the hash. | ||
* | ||
* @param {string} url - URL | ||
* @returns {string} Fragment from URL, without the hash | ||
*/ | ||
SkipLink.prototype.getFragmentFromUrl = function (url) { | ||
if (url.indexOf('#') === -1) { | ||
return false | ||
} | ||
|
||
return url.split('#').pop() | ||
} | ||
|
||
export default SkipLink |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* eslint-env jest */ | ||
|
||
const configPaths = require('../../../../config/paths.json') | ||
const PORT = configPaths.ports.test | ||
|
||
const baseUrl = 'http://localhost:' + PORT | ||
|
||
describe('/examples/template-default', () => { | ||
describe('skip link', () => { | ||
beforeAll(async () => { | ||
await page.goto(`${baseUrl}/examples/template-default`, { waitUntil: 'load' }) | ||
await page.keyboard.press('Tab') | ||
await page.keyboard.press('Enter') | ||
}) | ||
|
||
it('focuses the linked element', async () => { | ||
const activeElement = await page.evaluate(() => document.activeElement.id) | ||
|
||
expect(activeElement).toBe('main-content') | ||
}) | ||
|
||
it('adds the tabindex attribute to the linked element', async () => { | ||
const tabindex = await page.$eval('.govuk-main-wrapper', el => el.getAttribute('tabindex')) | ||
|
||
expect(tabindex).toBe('-1') | ||
}) | ||
|
||
it('adds the class for removing the native focus style to the linked element', async () => { | ||
const cssClass = await page.$eval('.govuk-main-wrapper', el => el.classList.contains('govuk-skip-link-focused-element')) | ||
|
||
expect(cssClass).toBeTruthy() | ||
}) | ||
|
||
it('removes the tabindex attribute from the linked element on blur', async () => { | ||
await page.$eval('.govuk-main-wrapper', el => el.blur()) | ||
|
||
const tabindex = await page.$eval('.govuk-main-wrapper', el => el.getAttribute('tabindex')) | ||
|
||
expect(tabindex).toBeNull() | ||
}) | ||
|
||
it('removes the class for removing the native focus style from the linked element on blur', async () => { | ||
await page.$eval('.govuk-main-wrapper', el => el.blur()) | ||
|
||
const cssClass = await page.$eval('.govuk-main-wrapper', el => el.getAttribute('class')) | ||
|
||
expect(cssClass).not.toContain('govuk-skip-link-focused-element') | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
<a href="{{ params.href | default('#content') }}" class="govuk-skip-link{%- if params.classes %} {{ params.classes }}{% endif -%}"{%- for attribute, value in params.attributes %} {{ attribute }}="{{ value }}"{% endfor %}> | ||
<a href="{{ params.href | default('#content') }}" class="govuk-skip-link{%- if params.classes %} {{ params.classes }}{% endif -%}"{%- for attribute, value in params.attributes %} {{ attribute }}="{{ value }}"{% endfor %} data-module="govuk-skip-link"> | ||
{{- params.html | safe if params.html else params.text -}} | ||
</a> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters