Skip to content

Commit

Permalink
Merge pull request #1497 from alphagov/radio-trigger-setattributes
Browse files Browse the repository at this point in the history
Users can now conditionally reveal content on pages with multiple grouped radios
  • Loading branch information
NickColley authored Jul 23, 2019
2 parents f73a6e1 + 8665fa5 commit 0bce5fc
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ GOV.UK Template's focused link colour no longer overrides GOV.UK Frontend](https
- [Pull request #1434: The underline below links no longer sits too far down in Firefox](https://github.com/alphagov/govuk-frontend/pull/1434).
- [Pull request #1435: When a user resubmits a form, the error summary is now correctly focused instead of the form](https://github.com/alphagov/govuk-frontend/pull/1435).
- [Pull request #1473: We’ve removed icon-arrow-left.png and icon-important.png, because they were not used in GOV.UK Frontend](https://github.com/alphagov/govuk-frontend/pull/1473)
- [Pull request #1497: Users can now conditionally reveal content on pages with multiple grouped radios](https://github.com/alphagov/govuk-frontend/pull/1497) - thanks to [@colinrotherham](https://github.com/colinrotherham) and [@frankieroberto](https://github.com/frankieroberto) for their help.

## 2.13.0

Expand Down
176 changes: 176 additions & 0 deletions app/views/examples/multiple-radio-groups/index.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
{% extends "layout.njk" %}

{% from "back-link/macro.njk" import govukBackLink %}
{% from "button/macro.njk" import govukButton %}
{% from "radios/macro.njk" import govukRadios %}

{% block beforeContent %}
{{ govukBackLink({
"href": "/"
}) }}
{% endblock %}

{% block content %}
<h1 class="govuk-heading-xl">Multiple radio groups</h1>

<div class="govuk-grid-row">
<div class="govuk-grid-column-one-half">
<form method="get" novalidate>
<fieldset class="govuk-fieldset">
<legend class="govuk-fieldset__legend govuk-fieldset__legend--l">
<h2 class="govuk-fieldset__heading">
What is your favourite colour?
</h2>
</legend>
<h3 class="govuk-heading-m">Warm colours</h3>
{{ govukRadios({
idPrefix: "warm",
name: "colour",
items: [
{
value: "red",
text: "Red",
conditional: {
html: '<p class="govuk-body">Nice choice, I like red too.</p>'
}
},
{
value: "orange",
text: "Orange",
conditional: {
html: '<p class="govuk-body">Nice choice, I like orange too.</p>'
}
}
]
}) }}

<h3 class="govuk-heading-m">Cool colours</h3>
{{ govukRadios({
idPrefix: "cool",
name: "colour",
items: [
{
value: "blue",
text: "Blue",
conditional: {
html: '<p class="govuk-body">Nice choice, I like blue too.</p>'
}
},
{
value: "green",
text: "Green",
conditional: {
html: '<p class="govuk-body">Boo, you monster...</p>'
}
}
]
}) }}

<h3 class="govuk-heading-m">Do you like colours in general?</h3>
{{ govukRadios({
idPrefix: "colours-in-general",
name: "colours-in-general",
items: [
{
value: "yes",
text: "Yes",
conditional: {
html: '<p class="govuk-body">Fair enough.</p>'
}
},
{
value: "no",
text: "No",
conditional: {
html: '<p class="govuk-body">No judgment.</p>'
}
}
]
}) }}
</fieldset>
{{ govukButton({
text: "Submit"
}) }}
</form>
</div>
<div class="govuk-grid-column-one-half">
<form method="get" novalidate>
<fieldset class="govuk-fieldset">
<legend class="govuk-fieldset__legend govuk-fieldset__legend--l">
<h2 class="govuk-fieldset__heading">
What is your least favourite colour?
</h2>
</legend>
<h3 class="govuk-heading-m">Warm colours</h3>
{{ govukRadios({
idPrefix: "least-warm",
name: "colour",
items: [
{
value: "red",
text: "Red",
conditional: {
html: '<p class="govuk-body">Nice choice, I like red too.</p>'
}
},
{
value: "orange",
text: "Orange",
conditional: {
html: '<p class="govuk-body">Nice choice, I like orange too.</p>'
}
}
]
}) }}

<h3 class="govuk-heading-m">Cool colours</h3>
{{ govukRadios({
idPrefix: "least-cool",
name: "colour",
items: [
{
value: "blue",
text: "Blue",
conditional: {
html: '<p class="govuk-body">Nice choice, I like blue too.</p>'
}
},
{
value: "green",
text: "Green",
conditional: {
html: '<p class="govuk-body">Boo, you monster...</p>'
}
}
]
}) }}
</fieldset>
{{ govukButton({
text: "Submit"
}) }}
</form>

<h3 class="govuk-heading-m">A question that is not in a form</h3>
{{ govukRadios({
idPrefix: "question-not-in-form",
name: "question-not-in-form",
items: [
{
value: "yes",
text: "Yes",
conditional: {
html: '<p class="govuk-body">Fair enough.</p>'
}
},
{
value: "no",
text: "No",
conditional: {
html: '<p class="govuk-body">No judgment.</p>'
}
}
]
}) }}
</div>
</div>
{% endblock %}
35 changes: 24 additions & 11 deletions src/govuk/components/radios/radios.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ import { nodeListForEach } from '../../common'

function Radios ($module) {
this.$module = $module
this.$inputs = $module.querySelectorAll('input[type="radio"]')
}

Radios.prototype.init = function () {
var $module = this.$module
var $inputs = this.$inputs
var $inputs = $module.querySelectorAll('input[type="radio"]')

/**
* Loop over all items with [data-controls]
Expand All @@ -37,21 +36,35 @@ Radios.prototype.init = function () {
}

Radios.prototype.setAttributes = function ($input) {
var inputIsChecked = $input.checked
$input.setAttribute('aria-expanded', inputIsChecked)
var $content = document.querySelector('#' + $input.getAttribute('aria-controls'))

if ($content && $content.classList.contains('govuk-radios__conditional')) {
var inputIsChecked = $input.checked

$input.setAttribute('aria-expanded', inputIsChecked)

var $content = this.$module.querySelector('#' + $input.getAttribute('aria-controls'))
if ($content) {
$content.classList.toggle('govuk-radios__conditional--hidden', !inputIsChecked)
}
}

Radios.prototype.handleClick = function (event) {
nodeListForEach(this.$inputs, function ($input) {
// If a radio with aria-controls, handle click
var isRadio = $input.getAttribute('type') === 'radio'
var hasAriaControls = $input.getAttribute('aria-controls')
if (isRadio && hasAriaControls) {
var $clickedInput = event.target
// We only want to handle clicks for radio inputs
if ($clickedInput.type !== 'radio') {
return
}
// Because checking one radio can uncheck a radio in another $module,
// we need to call set attributes on all radios in the same form, or document if they're not in a form.
//
// We also only want radios which have aria-controls, as they support conditional reveals.
var $allInputs = document.querySelectorAll('input[type="radio"][aria-controls]')
nodeListForEach($allInputs, function ($input) {
// Only inputs with the same form owner should change.
var hasSameFormOwner = ($input.form === $clickedInput.form)

// In radios, only radios with the same name will affect each other.
var hasSameName = ($input.name === $clickedInput.name)
if (hasSameName && hasSameFormOwner) {
this.setAttributes($input)
}
}.bind(this))
Expand Down
24 changes: 24 additions & 0 deletions src/govuk/components/radios/radios.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,29 @@ describe('Radios with conditional reveals', () => {
const isContentHidden = await waitForHiddenSelector(`[id="${firstInputAriaControls}"]`)
expect(isContentHidden).toBeTruthy()
})

describe('with multiple radio groups on the same page', () => {
it('toggles conditional reveals in other groups', async () => {
await page.goto(baseUrl + '/examples/multiple-radio-groups', { waitUntil: 'load' })

// Select red in warm colours
await page.click('#warm')

// Select blue in cool colours
await page.click('#cool')

const isWarmConditionalRevealHidden = await waitForHiddenSelector('#conditional-warm')
expect(isWarmConditionalRevealHidden).toBeTruthy()
})
it('toggles conditional reveals when not in a form', async () => {
await page.goto(baseUrl + '/examples/multiple-radio-groups', { waitUntil: 'load' })

// Select first input in radios not in a form
await page.click('#question-not-in-form')

const isConditionalRevealVisible = await waitForVisibleSelector('#conditional-question-not-in-form')
expect(isConditionalRevealVisible).toBeTruthy()
})
})
})
})

0 comments on commit 0bce5fc

Please sign in to comment.