Skip to content

Commit

Permalink
PATCH: Remove aria-controls and aria-expanded from va-accordion exp…
Browse files Browse the repository at this point in the history
…and all button (#1400)

* PATCH: Remove aria-controls and aria-expanded from va-accordion expand all button.
* Removed two ARIA attributes from Expand all button.
* Removed ARIA attributes from va-accordion e2e test.
* Restored aria-expanded attribute and test HTML.
* Added data-testid for Cypress helpers.
  • Loading branch information
1Copenut authored Dec 10, 2024
1 parent 2404461 commit f9c93b8
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('va-accordion', () => {
<va-accordion class="hydrated">
<mock:shadow-root>
<div class="usa-accordion">
<button aria-controls="" aria-expanded="false" aria-label="expand-all-aria-label" class="va-accordion__button">
<button aria-expanded="false" aria-label="expand-all-aria-label" class="va-accordion__button" data-testid="expand-all-accordions">
expand-all +
</button>
<slot></slot>
Expand Down
166 changes: 84 additions & 82 deletions packages/web-components/src/components/va-accordion/va-accordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,85 +87,88 @@ export class VaAccordion {

@Listen('accordionItemToggled')
itemToggledHandler(event: CustomEvent) {
// eslint-disable-next-line i18next/no-literal-string
const clickedItem = (event.target as HTMLElement).closest('va-accordion-item');
// Usage for slot to provide context to analytics for header and level
const header = clickedItem.querySelector('[slot="headline"]');
// using the slot to provide context to analytics for header and level
let headerText
let headerLevel
if (header) {
headerText = header?.innerHTML
headerLevel = parseInt(header?.tagName?.toLowerCase().split('')[1]);
} else {
// using the props to provide context to analytics for header and level
headerText = clickedItem.header
headerLevel = clickedItem.level
}

if (this.openSingle) {
getSlottedNodes(this.el, 'va-accordion-item')
.filter(item => item !== clickedItem)
/* eslint-disable-next-line i18next/no-literal-string */
.forEach(item => (item as Element).setAttribute('open', 'false'));
}

const prevAttr = clickedItem.getAttribute('open') === 'true' ? true : false;

if (!this.disableAnalytics) {

const detail = {
componentName: 'va-accordion',
action: prevAttr ? 'collapse' : 'expand',
details: {
header: headerText || clickedItem.header,
subheader: clickedItem.subheader,
level: headerLevel || clickedItem.level,
sectionHeading: this.sectionHeading,
},
};
this.componentLibraryAnalytics.emit(detail);
}

/* eslint-disable-next-line i18next/no-literal-string */
clickedItem.setAttribute('open', !prevAttr ? "true" : "false");

if (!this.isScrolledIntoView(clickedItem)) {
clickedItem.scrollIntoView();
}

// Check if all accordions are open or closed due to user clicks
this.accordionsOpened();
// eslint-disable-next-line i18next/no-literal-string
const clickedItem = (event.target as HTMLElement).closest(
'va-accordion-item',
);
// Usage for slot to provide context to analytics for header and level
const header = clickedItem.querySelector('[slot="headline"]');
// using the slot to provide context to analytics for header and level
let headerText;
let headerLevel;
if (header) {
headerText = header?.innerHTML;
headerLevel = parseInt(header?.tagName?.toLowerCase().split('')[1]);
} else {
// using the props to provide context to analytics for header and level
headerText = clickedItem.header;
headerLevel = clickedItem.level;
}

if (this.openSingle) {
getSlottedNodes(this.el, 'va-accordion-item')
.filter(item => item !== clickedItem)
/* eslint-disable-next-line i18next/no-literal-string */
.forEach(item => (item as Element).setAttribute('open', 'false'));
}

const prevAttr = clickedItem.getAttribute('open') === 'true' ? true : false;

if (!this.disableAnalytics) {
const detail = {
componentName: 'va-accordion',
action: prevAttr ? 'collapse' : 'expand',
details: {
header: headerText || clickedItem.header,
subheader: clickedItem.subheader,
level: headerLevel || clickedItem.level,
sectionHeading: this.sectionHeading,
},
};
this.componentLibraryAnalytics.emit(detail);
}

/* eslint-disable-next-line i18next/no-literal-string */
clickedItem.setAttribute('open', !prevAttr ? 'true' : 'false');

if (!this.isScrolledIntoView(clickedItem)) {
clickedItem.scrollIntoView();
}

// Check if all accordions are open or closed due to user clicks
this.accordionsOpened();
}

/**
* Handles the accordion open state
* @param method "some" or "every"; array methods to check if all or some of the accordion items are open
*/
private accordionsOpened(method='every') {
private accordionsOpened(method = 'every') {
// Track user clicks on va-accordion-item within an array to compare if all values are true or false
const accordionItems = [...this.el.children]
.filter((el) => el.tagName.toLowerCase() === 'va-accordion-item')
.map((el) => el.open);
.filter(el => el.tagName.toLowerCase() === 'va-accordion-item')
.map(el => el.open);

const allOpen = currentValue => currentValue === true;
const allClosed = currentValue => currentValue === false;

if (accordionItems[method](allOpen)) {
return this.expanded = true;
return (this.expanded = true);
}

if (accordionItems[method](allClosed)) {
return this.expanded = false;
return (this.expanded = false);
}
}

// Expand or Collapse All Function for Button Click
private expandCollapseAll = (expanded: boolean) => {
this.expanded = expanded;
getSlottedNodes(this.el, 'va-accordion-item').forEach((item:HTMLElement) => {
item.setAttribute('open', `${expanded}`)
});
getSlottedNodes(this.el, 'va-accordion-item').forEach(
(item: HTMLElement) => {
item.setAttribute('open', `${expanded}`);
},
);
};

isScrolledIntoView(el: Element) {
Expand Down Expand Up @@ -201,36 +204,35 @@ export class VaAccordion {
'usa-accordion': true,
});

const accordionItemIDs = [...this.el.children]
.filter((el) => el.tagName.toLowerCase() === 'va-accordion-item')
.map((el) => el.id);

return (
<Host>
<div class={ accordionClass } ref={(accordionContainer) => this.accordionContainer = accordionContainer}>
{
!openSingle ? (
<button
class="va-accordion__button"
ref={el => (this.expandCollapseBtn = el as HTMLButtonElement)}
onClick={() => this.expandCollapseAll(!this.expanded)}
aria-label={
this.expanded
? i18next.t('collapse-all-aria-label')
: i18next.t('expand-all-aria-label')
}
aria-controls={accordionItemIDs.join(' ')}
aria-expanded={`${this.expanded}`}
>
{this.expanded
? `${i18next.t('collapse-all')} -`
: `${i18next.t('expand-all')} +`}
</button>
) : null
<div
class={accordionClass}
ref={accordionContainer =>
(this.accordionContainer = accordionContainer)
}
>
{!openSingle ? (
<button
aria-expanded={`${this.expanded}`}
class="va-accordion__button"
data-testid="expand-all-accordions"
ref={el => (this.expandCollapseBtn = el as HTMLButtonElement)}
onClick={() => this.expandCollapseAll(!this.expanded)}
aria-label={
this.expanded
? i18next.t('collapse-all-aria-label')
: i18next.t('expand-all-aria-label')
}
>
{this.expanded
? `${i18next.t('collapse-all')} -`
: `${i18next.t('expand-all')} +`}
</button>
) : null}
<slot></slot>
</div>
</Host>
)
);
}
}

0 comments on commit f9c93b8

Please sign in to comment.