From 5ffb403f2c535d8a3d69586ca89d8129658fefb2 Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Thu, 12 Sep 2024 08:51:49 -0500 Subject: [PATCH] Add message-aria-describedby to checkbox group (#1327) --- .../va-checkbox-group-uswds.stories.jsx | 13 ++++++++++-- packages/web-components/src/components.d.ts | 8 ++++++++ .../test/va-checkbox-group.e2e.ts | 8 ++++++++ .../va-checkbox-group/va-checkbox-group.tsx | 20 ++++++++++++++----- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/packages/storybook/stories/va-checkbox-group-uswds.stories.jsx b/packages/storybook/stories/va-checkbox-group-uswds.stories.jsx index 1c893961b..420dbfc6b 100644 --- a/packages/storybook/stories/va-checkbox-group-uswds.stories.jsx +++ b/packages/storybook/stories/va-checkbox-group-uswds.stories.jsx @@ -33,6 +33,7 @@ const vaCheckboxGroup = args => { required, hint, 'label-header-level': labelHeaderLevel, + 'message-aria-describedby': messageAriaDescribedby, ...rest } = args; return ( @@ -43,6 +44,7 @@ const vaCheckboxGroup = args => { required={required} hint={hint} label-header-level={labelHeaderLevel} + message-aria-describedby={messageAriaDescribedby} > @@ -152,6 +154,7 @@ const defaultArgs = { 'form-heading-level': null, 'form-heading': null, 'form-description': null, + 'message-aria-describedby': null, }; export const Default = Template.bind(null); @@ -206,7 +209,7 @@ const FormsPatternMultipleTemplate = ({ label, required, tile, - 'message-aria-describedby': messageAriaDescribedBy, + 'message-aria-describedby': messageAriaDescribedby, }) => { const handleClick = () => { const header = document @@ -292,7 +295,7 @@ const FormsPatternSingleTemplate = ({ error, label, required, - 'message-aria-describedby': messageAriaDescribedBy, + 'message-aria-describedby': messageAriaDescribedby, }) => { const id = Math.floor(Math.random() * 10) + 1; const handleClick = () => { @@ -362,6 +365,12 @@ Tile.args = { label: 'Select any historical figure', }; +export const withDescriptionMessage = Template.bind(null); +withDescriptionMessage.args = { + ...defaultArgs, + 'message-aria-describedby': 'some additional info', +}; + export const Internationalization = I18nTemplate.bind(null); Internationalization.args = { ...defaultArgs, diff --git a/packages/web-components/src/components.d.ts b/packages/web-components/src/components.d.ts index 8ce2d7e72..7c90f1bea 100644 --- a/packages/web-components/src/components.d.ts +++ b/packages/web-components/src/components.d.ts @@ -426,6 +426,10 @@ export namespace Components { * Insert a header with defined level inside the label (legend) */ "labelHeaderLevel"?: string; + /** + * An optional message that will be read by screen readers when a checkbox is focused. + */ + "messageAriaDescribedby"?: string; /** * Whether or not this input field is required. */ @@ -3437,6 +3441,10 @@ declare namespace LocalJSX { * Insert a header with defined level inside the label (legend) */ "labelHeaderLevel"?: string; + /** + * An optional message that will be read by screen readers when a checkbox is focused. + */ + "messageAriaDescribedby"?: string; /** * The event used to track usage of the component. This is emitted when an input value changes and enableAnalytics is true. */ diff --git a/packages/web-components/src/components/va-checkbox-group/test/va-checkbox-group.e2e.ts b/packages/web-components/src/components/va-checkbox-group/test/va-checkbox-group.e2e.ts index 826d0af06..c705c6923 100644 --- a/packages/web-components/src/components/va-checkbox-group/test/va-checkbox-group.e2e.ts +++ b/packages/web-components/src/components/va-checkbox-group/test/va-checkbox-group.e2e.ts @@ -171,6 +171,14 @@ describe('va-checkbox-group', () => { `); }); + it('renders aria message text if included', async () => { + const page = await newE2EPage(); + await page.setContent(''); + const message = await page.find('va-checkbox-group >>> #description-message'); + expect(message.textContent).toEqual("Some additional info"); + expect(message).toHaveClass("usa-sr-only"); + }); + it('useFormsPattern displays header for the single field pattern', async () => { const page = await newE2EPage(); await page.setContent( diff --git a/packages/web-components/src/components/va-checkbox-group/va-checkbox-group.tsx b/packages/web-components/src/components/va-checkbox-group/va-checkbox-group.tsx index c0b944ca3..f0950911c 100644 --- a/packages/web-components/src/components/va-checkbox-group/va-checkbox-group.tsx +++ b/packages/web-components/src/components/va-checkbox-group/va-checkbox-group.tsx @@ -67,6 +67,10 @@ export class VaCheckboxGroup { * Insert a header with defined level inside the label (legend) */ @Prop() labelHeaderLevel?: string; + /** + * An optional message that will be read by screen readers when a checkbox is focused. + */ + @Prop() messageAriaDescribedby?: string; /** * Enabling this will add a heading and description for integrating into the forms pattern. Accepts `single` or `multiple` to indicate if the form is a single input or will have multiple inputs. */ @@ -76,7 +80,7 @@ export class VaCheckboxGroup { * The heading level for the heading if `useFormsPattern` is true. */ @Prop() formHeadingLevel?: number = 3; - + /** * The content of the heading if `useFormsPattern` is true. */ @@ -132,15 +136,16 @@ export class VaCheckboxGroup { required, error, hint, + messageAriaDescribedby, useFormsPattern, formHeadingLevel, formHeading, } = this; const HeaderLevel = this.getHeaderLevel(); - const ariaLabeledByIds = - `${useFormsPattern && formHeading ? 'form-question' : ''} ${ + const ariaLabeledByIds = + `${useFormsPattern && formHeading ? 'form-question' : ''} ${ useFormsPattern ? 'form-description' : ''} ${ useFormsPattern === 'multiple' ? 'header-message' : ''}`.trim() || null; - + const messageAriaDescribedbyId = messageAriaDescribedby ? 'description-message' : null; const legendClass = classnames({ 'usa-legend': true, @@ -170,7 +175,7 @@ export class VaCheckboxGroup { {formsHeading}
- + {HeaderLevel ? ( {label} ) : ( @@ -183,6 +188,11 @@ export class VaCheckboxGroup { ) } + {messageAriaDescribedby && ( + + {messageAriaDescribedby} + + )} {required && {i18next.t('required')}} {hint &&
{hint}
}