Skip to content

Commit 29e890b

Browse files
authored
Add default ErrorSummary attributes (#229)
* Add default ErrorSummary attributes * Remove attributes from ErrorSummary in storybook
1 parent 28e322c commit 29e890b

File tree

4 files changed

+63
-10
lines changed

4 files changed

+63
-10
lines changed

src/components/form-elements/error-summary/ErrorSummary.tsx

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,19 @@ import React, {
77
RefAttributes,
88
} from 'react';
99
import classNames from 'classnames';
10+
import useDevWarning from '@util/hooks/UseDevWarning';
1011

11-
const ErrorSummaryTitle: FC<HTMLProps<HTMLHeadingElement>> = ({ className, ...rest }) => (
12-
<h2 className={classNames('nhsuk-error-summary__title', className)} {...rest} />
12+
const DefaultErrorSummaryTitleID = 'error-summary-title';
13+
14+
const ErrorSummaryTitle: FC<HTMLProps<HTMLHeadingElement>> = ({
15+
className,
16+
id = DefaultErrorSummaryTitleID,
17+
...rest
18+
}) => (
19+
<h2 className={classNames('nhsuk-error-summary__title', className)} id={id} {...rest} />
1320
);
1421

22+
1523
const ErrorSummaryBody: FC<HTMLProps<HTMLDivElement>> = ({ className, ...rest }) => (
1624
<div className={classNames('nhsuk-error-summary__body', className)} {...rest} />
1725
);
@@ -37,10 +45,31 @@ interface ErrorSummary
3745
}
3846

3947
const ErrorSummaryDiv = forwardRef<HTMLDivElement, HTMLProps<HTMLDivElement>>(
40-
({ className, ...rest }, ref) => (
41-
<div className={classNames('nhsuk-error-summary', className)} ref={ref} {...rest} />
42-
),
43-
);
48+
({
49+
className,
50+
tabIndex = -1,
51+
role = 'alert',
52+
'aria-labelledby': ariaLabelledBy = DefaultErrorSummaryTitleID,
53+
...rest
54+
},
55+
ref
56+
) => {
57+
useDevWarning('The ErrorSummary component should always have a tabIndex of -1', () => tabIndex !== -1)
58+
useDevWarning('The ErrorSummary component should always have a role of alert', () => role !== 'alert')
59+
60+
return (
61+
<div
62+
className={classNames('nhsuk-error-summary', className)}
63+
ref={ref}
64+
tabIndex={tabIndex}
65+
role={role}
66+
aria-labelledby={ariaLabelledBy}
67+
{...rest}
68+
/>
69+
)
70+
});
71+
72+
4473
ErrorSummaryDiv.displayName = 'ErrorSummary';
4574

4675
const ErrorSummary: ErrorSummary = Object.assign(ErrorSummaryDiv, {

src/components/form-elements/error-summary/__tests__/ErrorSummary.test.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,26 @@ describe('ErrorSummary', () => {
1616
expect(ref.current).not.toBeNull();
1717
});
1818

19+
it('has default props', () => {
20+
const { container } = render(<ErrorSummary />);
21+
22+
expect(container.querySelector('div')?.getAttribute('tabindex')).toBe('-1');
23+
expect(container.querySelector('div')?.getAttribute('role')).toBe('alert');
24+
expect(container.querySelector('div')?.getAttribute('aria-labelledby')).toBe('error-summary-title');
25+
})
26+
27+
it('throws a dev warning if tabIndex is not -1', () => {
28+
jest.spyOn(console, 'warn').mockImplementation(() => {});
29+
render(<ErrorSummary tabIndex={0} />);
30+
expect(console.warn).toHaveBeenCalledWith('The ErrorSummary component should always have a tabIndex of -1');
31+
})
32+
33+
it('throws a dev warning if role is not alert', () => {
34+
jest.spyOn(console, 'warn').mockImplementation(() => {});
35+
render(<ErrorSummary role="status" />);
36+
expect(console.warn).toHaveBeenCalledWith('The ErrorSummary component should always have a role of alert');
37+
})
38+
1939
describe('ErrorSummary.Title', () => {
2040
it('matches snapshot', () => {
2141
const { container } = render(<ErrorSummary.Title>Title</ErrorSummary.Title>);

src/components/form-elements/error-summary/__tests__/__snapshots__/ErrorSummary.test.tsx.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ exports[`ErrorSummary ErrorSummary.Title matches snapshot: ErrorSummary.Title 1`
3434
<div>
3535
<h2
3636
class="nhsuk-error-summary__title"
37+
id="error-summary-title"
3738
>
3839
Title
3940
</h2>
@@ -43,7 +44,10 @@ exports[`ErrorSummary ErrorSummary.Title matches snapshot: ErrorSummary.Title 1`
4344
exports[`ErrorSummary matches snapshot: ErrorSummary 1`] = `
4445
<div>
4546
<div
47+
aria-labelledby="error-summary-title"
4648
class="nhsuk-error-summary"
49+
role="alert"
50+
tabindex="-1"
4751
/>
4852
</div>
4953
`;

stories/Form Elements/ErrorSummary.stories.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ import { Meta, StoryObj } from '@storybook/react';
2323
*
2424
* const Element = () => {
2525
* return (
26-
* <ErrorSummary aria-labelledby="error-summary-title" role="alert" tabIndex={-1}>
27-
* <ErrorSummary.Title id="error-summary-title">There is a problem</ErrorSummary.Title>
26+
* <ErrorSummary>
27+
* <ErrorSummary.Title>There is a problem</ErrorSummary.Title>
2828
* <ErrorSummary.Body>
2929
* <p>Optional description of the errors and how to correct them</p>
3030
* <ErrorSummary.List>
@@ -55,8 +55,8 @@ ErrorSummary.Item.displayName = 'ErrorSummary.Item';
5555

5656
export const Standard: Story = {
5757
render: (args) => (
58-
<ErrorSummary aria-labelledby="error-summary-title" role="alert" tabIndex={-1}>
59-
<ErrorSummary.Title id="error-summary-title">There is a problem</ErrorSummary.Title>
58+
<ErrorSummary>
59+
<ErrorSummary.Title>There is a problem</ErrorSummary.Title>
6060
<ErrorSummary.Body>
6161
<p>Optional description of the errors and how to correct them</p>
6262
<ErrorSummary.List>

0 commit comments

Comments
 (0)