Skip to content

Commit

Permalink
Merge pull request #1994 from alphagov/add-notifications-auto-focus
Browse files Browse the repository at this point in the history
  • Loading branch information
hannalaakso authored Oct 29, 2020
2 parents e47ccf0 + d9cc60a commit 52e001f
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 140 deletions.
6 changes: 6 additions & 0 deletions src/govuk/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Details from './components/details/details'
import CharacterCount from './components/character-count/character-count'
import Checkboxes from './components/checkboxes/checkboxes'
import ErrorSummary from './components/error-summary/error-summary'
import NotificationBanner from './components/notification-banner/notification-banner'
import Header from './components/header/header'
import Radios from './components/radios/radios'
import Tabs from './components/tabs/tabs'
Expand Down Expand Up @@ -50,6 +51,11 @@ function initAll (options) {
var $toggleButton = scope.querySelector('[data-module="govuk-header"]')
new Header($toggleButton).init()

var $notificationBanners = scope.querySelectorAll('[data-module="govuk-notification-banner"]')
nodeListForEach($notificationBanners, function ($notificationBanner) {
new NotificationBanner($notificationBanner).init()
})

var $radios = scope.querySelectorAll('[data-module="govuk-radios"]')
nodeListForEach($radios, function ($radio) {
new Radios($radio).init()
Expand Down
47 changes: 47 additions & 0 deletions src/govuk/components/notification-banner/notification-banner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
function NotificationBanner ($module) {
this.$module = $module
}

/**
* Initialise the component
*/
NotificationBanner.prototype.init = function () {
var $module = this.$module
// Check for module
if (!$module) {
return
}

this.setFocus()
}

/**
* Focus the element
*
* If `role="alert"` is set, focus the element to help some assistive technologies
* prioritise announcing it.
*
* You can turn off the auto-focus functionality by setting `data-disable-auto-focus="true"` in the
* component HTML. You might wish to do this based on user research findings, or to avoid a clash
* with another element which should be focused when the page loads.
*/
NotificationBanner.prototype.setFocus = function () {
var $module = this.$module

if ($module.getAttribute('data-disable-auto-focus') === 'true') {
return
}

if ($module.getAttribute('role') !== 'alert') {
return
}

// Set tabindex to -1 to make the element focusable with JavaScript.
if (!$module.getAttribute('tabindex')) {
$module.setAttribute('tabindex', '-1')
}

$module.focus()
}

export default NotificationBanner
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* eslint-env jest */

const configPaths = require('../../../../config/paths.json')
const PORT = configPaths.ports.test

const baseUrl = 'http://localhost:' + PORT

describe('/components/notification-banner/with-type-as-success', () => {
it('has the correct tabindex to be focused with JavaScript', async () => {
await page.goto(baseUrl + '/components/notification-banner/with-type-as-success/preview', { waitUntil: 'load' })

const tabindex = await page.$eval('.govuk-notification-banner', el => el.getAttribute('tabindex'))

expect(tabindex).toEqual('-1')
})

it('is automatically focused when the page loads', async () => {
await page.goto(baseUrl + '/components/notification-banner/with-type-as-success/preview', { waitUntil: 'load' })

const activeElement = await page.evaluate(() => document.activeElement.dataset.module)

expect(activeElement).toBe('govuk-notification-banner')
})
})

describe('components/notification-banner/auto-focus-disabled,-with-type-as-success/', () => {
describe('when auto-focus is disabled', () => {
it('does not have a tabindex attribute', async () => {
await page.goto(`${baseUrl}/components/notification-banner/auto-focus-disabled,-with-type-as-success/preview`, { waitUntil: 'load' })

const tabindex = await page.$eval('.govuk-notification-banner', el => el.getAttribute('tabindex'))

expect(tabindex).toBeFalsy()
})

it('does not focus the notification banner', async () => {
await page.goto(`${baseUrl}/components/notification-banner/auto-focus-disabled,-with-type-as-success/preview`, { waitUntil: 'load' })

const activeElement = await page.evaluate(() => document.activeElement.dataset.module)

expect(activeElement).not.toBe('govuk-notification-banner')
})
})
})

describe('components/notification-banner/role=alert-overridden-to-role=region,-with-type-as-success', () => {
describe('when role is not alert', () => {
it('does not have a tabindex attribute', async () => {
await page.goto(`${baseUrl}/components/notification-banner/role=alert-overridden-to-role=region,-with-type-as-success/preview`, { waitUntil: 'load' })

const tabindex = await page.$eval('.govuk-notification-banner', el => el.getAttribute('tabindex'))

expect(tabindex).toBeFalsy()
})

it('does not focus the notification banner', async () => {
await page.goto(`${baseUrl}/components/notification-banner/role=alert-overridden-to-role=region,-with-type-as-success/preview`, { waitUntil: 'load' })

const activeElement = await page.evaluate(() => document.activeElement.dataset.module)

expect(activeElement).not.toBe('govuk-notification-banner')
})
})
})
46 changes: 12 additions & 34 deletions src/govuk/components/notification-banner/notification-banner.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,14 @@ params:
type: string
required: false
description: Overrides the value of the `role` attribute for the notification banner. Defaults to `region`. If `type` is set to `success` or `error`, defaults to `alert`.
- name: tabindex
type: string/boolean
required: false
description: Overrides the value of the `tabindex` attribute for the notification banner. Not set by default. If `type` is set to `success` or `error`, defaults to `-1`; the attribute can be removed by setting `tabindex` to `false`;
- name: titleId
type: string
required: false
description: Overrides the value of the `id` attribute for the title. `id` used by the `aria-labelledby` attribute on the notification banner to provide information to users of assistive technologies. `id` defaults to `govuk-notification-banner-title` if `role` is set to `region`. If `type` is set to `success` or `error`, `id` is not rendered by default.
- name: autoFocus
- name: disableAutoFocus
type: boolean
required: false
description: Moves keyboard focus to the notification banner when the page loads. Defaults to `false`. If `type` is set to `success` or `error`, defaults to `true`.
description: If you set 'type' to 'success' or 'error', or 'role' to 'alert', JavaScript moves the keyboard focus to the notification banner when the page loads. To disable this behaviour, set 'disableAutoFocus' to 'true'.
- name: classes
type: string
required: false
Expand Down Expand Up @@ -87,6 +83,16 @@ examples:
<li><a href="#" class="govuk-notification-banner__link">government-strategy-v3-FINAL.pdf</a></li>
<li><a href="#" class="govuk-notification-banner__link">government-strategy-v4-FINAL-v2.pdf</a></li>
</ul>
- name: auto-focus disabled, with type as success
data:
type: success
disableAutoFocus: true
text: Email sent to example@email.com
- name: role=alert overridden to role=region, with type as success
data:
type: success
role: region
text: Email sent to example@email.com-

# Hidden examples are not shown in the review app, but are used for tests and HTML fixtures

Expand Down Expand Up @@ -142,34 +148,6 @@ examples:
data:
role: banner
text: This publication was withdrawn on 7 March 2014.
- name: role overridden to region
hidden: true
data:
type: success
role: region
text: Email sent to example@email.com-
- name: custom tabindex
hidden: true
data:
tabindex: 0
text: This publication was withdrawn on 7 March 2014.
- name: tabindex as false and type as success
hidden: true
data:
type: success
tabindex: false
text: Email sent to example@email.com
- name: autoFocus as true
hidden: true
data:
autoFocus: true
text: This publication was withdrawn on 7 March 2014.
- name: autoFocus as false and type as success
hidden: true
data:
type: success
autoFocus: false
text: Email sent to example@email.com

- name: classes
hidden: true
Expand Down
22 changes: 3 additions & 19 deletions src/govuk/components/notification-banner/template.njk
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,6 @@
{% set role = "region" %}
{% endif %}

{# Check whether to add `data-auto-focus="true"` which focuses the notification banner on page load #}
{% if params.autoFocus is defined %}
{% set autoFocus = params.autoFocus %}
{% elif successOrError %}
{% set autoFocus = true %}
{% endif %}

{% if params.tabindex is defined %}
{% set tabindex = params.tabindex %}
{# Make sure that success or error banner should be focused on page load #}
{% elif successOrError and autoFocus %}
{# Make the notification banner focusable #}
{% set tabindex = "-1" %}
{% endif %}

{%- if params.titleHtml %}
{% set title = params.titleHtml | safe %}
{%- elif params.title %}
Expand All @@ -43,11 +28,10 @@
{% set title = "Important" %}
{%- endif -%}

<div class="govuk-notification-banner {{ typeClass }} {%- if params.classes %} {{ params.classes }}{% endif -%}" role="{{ role }}"
{%- if tabindex or tabindex === 0 %} tabindex="{{ tabindex }}" {% endif %}
{%- if (role == "region") %} aria-labelledby="{{ params.titleId | default('govuk-notification-banner-title') }}" {%- endif -%}
<div class="govuk-notification-banner{% if typeClass %} {{ typeClass }}{% endif %}{% if params.classes %} {{ params.classes }}{% endif %}" role="{{ role }}"
{%- if (role == "region") %} aria-labelledby="{{ params.titleId | default('govuk-notification-banner-title')}}" {% endif -%}
data-module="govuk-notification-banner"
{%- if autoFocus -%} data-auto-focus="true"{% endif %}
{%- if params.disableAutoFocus %} data-disable-auto-focus="true"{% endif %}
{%- for attribute, value in params.attributes %} {{attribute}}="{{value}}"{% endfor %}>
<div class="govuk-notification-banner__header">
<h{{ params.titleHeadingLevel | default(2) }} class="govuk-notification-banner__title"{% if (role == "region" or params.titleId) %} id="{{ params.titleId | default('govuk-notification-banner-title') }}" {%- endif %}>
Expand Down
Loading

0 comments on commit 52e001f

Please sign in to comment.