Skip to content

Commit

Permalink
Fix aria attributes on error messages (#230)
Browse files Browse the repository at this point in the history
* Fix aria attributes on error messages
* Fix behaviour of aria-describedby in form components
  • Loading branch information
Tomdango authored Jun 10, 2024
1 parent 29e890b commit d033806
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ exports[`Checkboxes matches snapshot with boolean error 1`] = `
class="nhsuk-form-group nhsuk-form-group--error"
>
<div
aria-describedby="example--error-message"
class="nhsuk-checkboxes"
id="example"
>
Expand Down Expand Up @@ -262,6 +263,7 @@ exports[`Checkboxes matches snapshot with string error 1`] = `
Example error
</span>
<div
aria-describedby="example--error-message"
class="nhsuk-checkboxes"
id="example"
>
Expand Down
8 changes: 6 additions & 2 deletions src/util/FormGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,13 @@ const FormGroup = <T extends BaseFormElementRenderProps>(props: FormGroupProps<T
const errorID = `${elementID}--error-message`;
const hintID = `${elementID}--hint`;

const ariaDescribedBy = [
hint ? hintID : undefined,
error ? errorID : undefined,
].filter(Boolean);

const childProps = {
'aria-describedby': hint ? hintID : undefined,
'aria-labelledby': label ? labelID : undefined,
'aria-describedby': ariaDescribedBy.join(' ') || undefined,
error,
name: name || elementID,
id: elementID,
Expand Down
35 changes: 31 additions & 4 deletions src/util/__tests__/FormGroup.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,6 @@ describe('FormGroup', () => {
expect(renderProps!.id).toHaveLength(11);
expect(renderProps!.id).toContain('input');

expect(container.querySelector('input')?.getAttribute('aria-labelledby')).toBe(
`${renderProps!.id}--label`,
);
expect(container.querySelector('.nhsuk-label')?.getAttribute('id')).toBe(
`${renderProps!.id}--label`,
);
Expand All @@ -133,7 +130,6 @@ describe('FormGroup', () => {
expect(renderProps).not.toBe(null);
expect(renderProps!.id).toBe('testID');

expect(container.querySelector('input')?.getAttribute('aria-labelledby')).toBe('testID--label');
expect(container.querySelector('.nhsuk-label')?.getAttribute('id')).toBe('testID--label');
expect(container.querySelector('.nhsuk-label')?.getAttribute('for')).toBe('testID');
expect(container.querySelector('.nhsuk-label')?.textContent).toBe('This is a test label');
Expand All @@ -155,6 +151,7 @@ describe('FormGroup', () => {
expect(renderProps).not.toBe(null);
expect(renderProps!.id).toHaveLength(11);
expect(renderProps!.id).toContain('input');
expect(renderProps!['aria-describedby']).toBe(`${renderProps!.id}--error-message`);

expect(container.querySelector('.nhsuk-error-message')?.getAttribute('id')).toBe(
`${renderProps!.id}--error-message`,
Expand Down Expand Up @@ -182,6 +179,8 @@ describe('FormGroup', () => {

expect(renderProps).not.toBe(null);
expect(renderProps!.id).toBe('testID');
expect(renderProps!['aria-describedby']).toBe(`testID--error-message`);


expect(container.querySelector('.nhsuk-error-message')?.getAttribute('id')).toBe(
'testID--error-message',
Expand Down Expand Up @@ -240,4 +239,32 @@ describe('FormGroup', () => {

expect(await axe(html)).toHaveNoViolations();
});

it('should add hint ID and error ID to the aria-describedby of the input', () => {
const { container } = renderFormGroupComponent({
inputType: 'input',
id: 'error-and-hint',
error: 'This is an error',
hint: 'This is a hint',
// eslint-disable-next-line @typescript-eslint/no-unused-vars
children: ({ error, ...rest }) => <input {...rest} />,
});

const inputElement = container.querySelector('input');
expect(inputElement).not.toBeNull();
expect(inputElement?.getAttribute('aria-describedby')).toBe('error-and-hint--hint error-and-hint--error-message');
})

it('should have no aria-describedby when there is no hint or label', () => {
const { container } = renderFormGroupComponent({
inputType: 'input',
// eslint-disable-next-line @typescript-eslint/no-unused-vars
children: ({ error, ...rest }) => <input {...rest} />,
});

const inputElement = container.querySelector('input');
expect(inputElement).not.toBeNull();

expect(inputElement?.getAttribute('aria-describedby')).toBe(null);
});
});

0 comments on commit d033806

Please sign in to comment.