Skip to content

Commit

Permalink
Replace GOVUK Radios JS with NHSUK Radios JS
Browse files Browse the repository at this point in the history
This implements a Stimulus controller shim to enhance `nhsuk-radios`
using the custom JS from `nhsuk-frontend`.

Because we're using GOVUK Radios HTML but with NHSUK Radios styling, we
need to manually add a `nhsuk-radios--conditional` class to the root
element.

In addition, NHSUK Radios use `aria-controls` on the server-rendered
HTML, but GOVUK Radios use `data-aria-controls` and enhance it when JS
initialises. Using `data-aria-controls` is the better solution, because
it means that the attribute doesn't kick in in a no-JS situation.
  • Loading branch information
tvararu committed Jul 13, 2023
1 parent 0441864 commit 671a752
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 12 deletions.
9 changes: 0 additions & 9 deletions app/javascript/controllers/govuk_radios_controller.js

This file was deleted.

6 changes: 3 additions & 3 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ application.register(
GovukNotificationBannerController,
);

import GovukRadiosController from "./govuk_radios_controller";
application.register("govuk-radios", GovukRadiosController);

import GovukSkipLinkController from "./govuk_skip_link_controller";
application.register("govuk-skip-link", GovukSkipLinkController);

import GovukTabsController from "./govuk_tabs_controller";
application.register("govuk-tabs", GovukTabsController);

import NhsukRadiosController from "./nhsuk_radios_controller";
application.register("nhsuk-radios", NhsukRadiosController);
38 changes: 38 additions & 0 deletions app/javascript/controllers/nhsuk_radios_controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { application } from "./application";
import NhsukRadiosController from "./nhsuk_radios_controller";
import NhsukRadios from "nhsuk-frontend/packages/components/radios/radios";

jest.mock("nhsuk-frontend/packages/components/radios/radios");

// Creating HTML body structure
document.body.innerHTML = `
<div data-module="nhsuk-radios">
<input type="radio" data-aria-controls="target-id" />
<div id="target-id" class="nhsuk-radios__conditional"></div>
</div>
<div data-module="nhsuk-radios">
<input type="radio" />
</div>
`;

describe("NhsukRadiosController", () => {
beforeEach(() => {
application.register("nhsuk-radios", NhsukRadiosController);
});

test("should call NhsukRadios", () => {
expect(NhsukRadios).toHaveBeenCalledTimes(2);
});

test("should add 'nhsuk-radios--conditional' class", () => {
const elements = document.querySelectorAll('[data-module="nhsuk-radios"]');
expect(elements[0].classList).toContain("nhsuk-radios--conditional");
expect(elements[1].classList).not.toContain("nhsuk-radios--conditional");
});

test("should promote 'data-aria-controls' to 'aria-controls'", () => {
const radioInput = document.querySelector('input[type="radio"]');
expect(radioInput.getAttribute("aria-controls")).toEqual("target-id");
expect(radioInput.getAttribute("data-aria-controls")).toBeNull();
});
});
43 changes: 43 additions & 0 deletions app/javascript/controllers/nhsuk_radios_controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Controller } from "@hotwired/stimulus";
import NhsukRadios from "nhsuk-frontend/packages/components/radios/radios";

// Connects to data-module="nhsuk-radios"
export default class extends Controller {
connect() {
this.addConditionalClassIfNeeded();
this.promoteAriaControlsAttribute();

NhsukRadios();
}

// We use govuk-frontend radio button HTML, which doesn't use a --conditional
// modifier on the root element. NHSUK Radios require this in order to set up
// and initialise.
addConditionalClassIfNeeded() {
if (!this.element.querySelectorAll(".nhsuk-radios__conditional").length)
return;

this.element.classList.add("nhsuk-radios--conditional");
}

// Promote data-aria-controls attribute to a aria-controls attribute as per
// https://github.com/alphagov/govuk-frontend/blob/88fea750b5eb9c9d9f661405e68bfb59e59754b2/packages/govuk-frontend/src/govuk/components/radios/radios.mjs#L33-L34
promoteAriaControlsAttribute() {
const $inputs = this.element.querySelectorAll('input[type="radio"]');

$inputs.forEach(($input) => {
const targetId = $input.getAttribute("data-aria-controls");

// Skip radios without data-aria-controls attributes, or where the
// target element does not exist.
if (!targetId || !document.getElementById(targetId)) {
return;
}

// Promote the data-aria-controls attribute to a aria-controls attribute
// so that the relationship is exposed in the AOM
$input.setAttribute("aria-controls", targetId);
$input.removeAttribute("data-aria-controls");
});
}
}

0 comments on commit 671a752

Please sign in to comment.