Skip to content

Commit

Permalink
Add description id to aria-describedby
Browse files Browse the repository at this point in the history
  • Loading branch information
Mottie committed Aug 25, 2023
1 parent 57ab8db commit 2e4f091
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 19 deletions.
1 change: 1 addition & 0 deletions packages/web-components/assets/arrow-both.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/web-components/assets/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions packages/web-components/assets/green-check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/web-components/assets/icon-dot-gov.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/web-components/assets/icon-https.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions packages/web-components/assets/minus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions packages/web-components/assets/plus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions packages/web-components/assets/sort-arrow-down.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions packages/web-components/assets/sort-arrow-up.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/web-components/assets/sprite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ describe('va-checkbox', () => {
await page.setContent(
'<va-checkbox error="Something went horribly wrong" />',
);
const element = await page.find('va-checkbox >>> #error-message');
const element = await page.find('va-checkbox >>> #checkbox-error-message');
const input = await page.find('va-checkbox >>> input');
expect(input.getAttribute('aria-invalid')).toEqual('true');
expect(input.getAttribute('aria-describedby')).toEqual('checkbox-error-message');
expect(element.textContent).toContain('Something went horribly wrong');
});

Expand All @@ -58,7 +59,9 @@ describe('va-checkbox', () => {
'<va-checkbox><p slot="description">This is a description!</p></va-checkbox',
);
const element = await page.find('va-checkbox');
const inputEl = await page.find('va-checkbox >>> input');
expect(element).toEqualText('This is a description!');
expect(inputEl.getAttribute('aria-describedby')).toEqual('description');
});

// This test fails, but is here as documentation. The unknown slot and unnamed
Expand All @@ -79,10 +82,12 @@ describe('va-checkbox', () => {
'<va-checkbox description="Description prop"><p slot="description">Slotted description</p></va-checkbox',
);
const element = await page.find('va-checkbox');
const inputEl = await page.find('va-checkbox >>> input');
expect(element.shadowRoot.textContent).toContain('Description prop');
expect(
await page.find('va-checkbox >>> slot[name="description"]'),
).toBeNull();
expect(inputEl.getAttribute('aria-describedby')).toEqual('description');
});

it('adds new aria-describedby for error message', async () => {
Expand All @@ -91,7 +96,7 @@ describe('va-checkbox', () => {

// Render the error message text
const inputEl = await page.find('va-checkbox >>> input');
expect(inputEl.getAttribute('aria-describedby')).toContain('error-message');
expect(inputEl.getAttribute('aria-describedby')).toContain('checkbox-error-message');
});

it('adds aria-describedby input-message id', async () => {
Expand All @@ -103,6 +108,19 @@ describe('va-checkbox', () => {
expect(inputEl.getAttribute('aria-describedby')).toContain('input-message');
});

it('adds aria-describedby input-message, checkbox-error-message and description ids', async () => {
const page = await newE2EPage();
await page.setContent(
`<va-checkbox error="Something went horribly wrong" message-aria-describedby="This is a message">
<p slot="description">Slotted description</p>
</va-checkbox>`,
);

// Render the error message text
const inputEl = await page.find('va-checkbox >>> input');
expect(inputEl.getAttribute('aria-describedby')).toEqual('input-message checkbox-error-message description');
});

it('passes an aXe check', async () => {
const page = await newE2EPage();

Expand Down Expand Up @@ -157,6 +175,7 @@ describe('va-checkbox', () => {
required: false,
},
});
expect(inputEl.getAttribute('aria-describedby')).toEqual('description');
});

it("doesn't fire an analytics event when enableAnalytics is false", async () => {
Expand Down Expand Up @@ -263,6 +282,7 @@ describe('va-checkbox', () => {
const element = await page.find('va-checkbox >>> #checkbox-error-message');
const input = await page.find('va-checkbox >>> input');
expect(input.getAttribute('aria-invalid')).toEqual('true');
expect(input.getAttribute('aria-describedby')).toEqual('checkbox-error-message');
expect(element.textContent).toContain('Something went horribly wrong');
});

Expand All @@ -287,7 +307,9 @@ describe('va-checkbox', () => {
'<va-checkbox uswds><p slot="description">This is a description!</p></va-checkbox',
);
const element = await page.find('va-checkbox');
const inputEl = await page.find('va-checkbox >>> input');
expect(element).toEqualText('This is a description!');
expect(inputEl.getAttribute('aria-describedby')).toEqual('description');
});

it('uswds v3 should prefer rendering the description prop over the slotted element', async () => {
Expand All @@ -296,10 +318,12 @@ describe('va-checkbox', () => {
'<va-checkbox uswds description="Description prop"><p slot="description">Slotted description</p></va-checkbox',
);
const element = await page.find('va-checkbox');
const inputEl = await page.find('va-checkbox >>> input');
expect(element.shadowRoot.textContent).toContain('Description prop');
expect(
await page.find('va-checkbox >>> slot[name="description"]'),
).toBeNull();
expect(inputEl.getAttribute('aria-describedby')).toEqual('description');
});

it('uswds v3 adds new aria-describedby for error message', async () => {
Expand All @@ -320,6 +344,19 @@ describe('va-checkbox', () => {
await axeCheck(page);
});

it('uswds v3 adds aria-describedby input-message, checkbox-error-message and description ids', async () => {
const page = await newE2EPage();
await page.setContent(
`<va-checkbox uswds error="Something went horribly wrong" message-aria-describedby="This is a message">
<p slot="description">Slotted description</p>
</va-checkbox>`,
);

// Render the error message text
const inputEl = await page.find('va-checkbox >>> input');
expect(inputEl.getAttribute('aria-describedby')).toEqual('input-message checkbox-error-message description');
});

it('uswds v3 fires an analytics event when enableAnalytics is true', async () => {
const page = await newE2EPage();
await page.setContent(
Expand Down
45 changes: 28 additions & 17 deletions packages/web-components/src/components/va-checkbox/va-checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,20 +165,23 @@ export class VaCheckbox {
}

render() {
const {
error,
label,
required,
description,
checked,
hint,
const {
error,
label,
required,
description,
checked,
hint,
tile,
uswds,
checkboxDescription,
disabled,
uswds,
checkboxDescription,
disabled,
messageAriaDescribedby,
} = this;


const hasDescription = description || !!this.el.querySelector('[slot="description"]');

if (uswds) {
const inputClass = classnames({
'usa-checkbox__input': true,
Expand All @@ -188,11 +191,15 @@ export class VaCheckbox {
'usa-legend': true,
'usa-label--error': error
});
const ariaDescribedbyIds = `${messageAriaDescribedby ? 'input-message' : ''} ${error ? 'checkbox-error-message' : ''}`
.trim() || null; // Null so we don't add the attribute if we have an empty string
const ariaDescribedbyIds = [
messageAriaDescribedby ? 'input-message' : '',
error ? 'checkbox-error-message' : '',
hasDescription ? 'description' : '',
// Return null so we don't add the attribute if we have an empty string
].filter(Boolean).join(' ').trim() || null;
return (
<Host>
{description ?
{description ?
<legend id="description" class={descriptionClass}>{description}</legend> :
<slot name="description" />
}
Expand All @@ -201,7 +208,7 @@ export class VaCheckbox {
<span id="checkbox-error-message" role="alert">
{error && (
<Fragment>
<span class="usa-sr-only">{i18next.t('error')}</span>
<span class="usa-sr-only">{i18next.t('error')}</span>
<span class="usa-error-message">{error}</span>
</Fragment>
)}
Expand Down Expand Up @@ -231,15 +238,19 @@ export class VaCheckbox {
</Host>
);
} else {
const ariaDescribedbyIds = `${messageAriaDescribedby ? 'input-message' : ''} ${error ? 'error-message' : ''}`
.trim() || null; // Null so we don't add the attribute if we have an empty string
const ariaDescribedbyIds = [
messageAriaDescribedby ? 'input-message' : '',
error ? 'checkbox-error-message' : '',
hasDescription ? 'description' : '',
// Return null so we don't add the attribute if we have an empty string
].filter(Boolean).join(' ').trim() || null;
return (
<Host>
<div id="description">
{description ? <p>{description}</p> : <slot name="description" />}
</div>
{hint && <span class="hint-text">{hint}</span>}
<span id="error-message" role="alert">
<span id="checkbox-error-message" role="alert">
{error && (
<Fragment>
<span class="sr-only">{i18next.t('error')}</span> {error}
Expand Down

0 comments on commit 2e4f091

Please sign in to comment.