Skip to content

Commit 0fb6736

Browse files
authored
feat(ui5-dynamic-side-content): add 'role' property to accessibilityAttributes object (#13476)
Until now, there were hardcoded roles for main (role="main") and side (role="complementary") containers of the `ui5-dynamic-side-content` component. In general case that is fine, but there are use cases where the component is placed in another landscape component that already has role="main" attribute, which produces Accessibility issues. This PR introduces new property `role` in the `accessibilityAttributes` object of the component both for main and side containers. Now the developer has three options for role: - if `role` property is not defined, the `role` attributes of main or side content container keeps the existing values ("main" for main content and "complementary" for side content; - if `role` property is set to some string value, it is populated in corresponding `role` attribute ot main or side content; - if `role` property is set to **undefined**, the `role` attribute is completely removed.
1 parent 6202009 commit 0fb6736

4 files changed

Lines changed: 92 additions & 7 deletions

File tree

packages/fiori/cypress/specs/DynamicSideContent.cy.tsx

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,77 @@ describe("Accessibility", () => {
8080
.find(".ui5-dsc-side")
8181
.should("have.attr", "aria-label", customSideContentLabel);
8282
});
83+
84+
it("tests no role when explicitly set to undefined via accessibilityAttributes", () => {
85+
cy.mount(
86+
<DynamicSideContent>
87+
<div>
88+
<h1>Main Content</h1>
89+
</div>
90+
<div slot="sideContent">
91+
<h1>Side Content</h1>
92+
</div>
93+
</DynamicSideContent>
94+
);
95+
96+
cy.get("[ui5-dynamic-side-content]")
97+
.as("dsc");
98+
99+
cy.get<DynamicSideContent>("@dsc")
100+
.then($dsc => {
101+
$dsc.get(0).accessibilityAttributes = {
102+
mainContent: { role: undefined },
103+
sideContent: { role: undefined },
104+
};
105+
});
106+
107+
cy.get("@dsc")
108+
.shadow()
109+
.find(".ui5-dsc-main")
110+
.should("not.have.attr", "role");
111+
112+
cy.get("@dsc")
113+
.shadow()
114+
.find(".ui5-dsc-side")
115+
.should("not.have.attr", "role");
116+
});
117+
118+
it("tests custom roles via accessibilityAttributes", () => {
119+
const customMainRole = "region";
120+
const customSideRole = "note";
121+
122+
cy.mount(
123+
<DynamicSideContent>
124+
<div>
125+
<h1>Main Content</h1>
126+
</div>
127+
<div slot="sideContent">
128+
<h1>Side Content</h1>
129+
</div>
130+
</DynamicSideContent>
131+
);
132+
133+
cy.get("[ui5-dynamic-side-content]")
134+
.as("dsc");
135+
136+
cy.get<DynamicSideContent>("@dsc")
137+
.then($dsc => {
138+
$dsc.get(0).accessibilityAttributes = {
139+
mainContent: { role: customMainRole },
140+
sideContent: { role: customSideRole },
141+
};
142+
});
143+
144+
cy.get("@dsc")
145+
.shadow()
146+
.find(".ui5-dsc-main")
147+
.should("have.attr", "role", customMainRole);
148+
149+
cy.get("@dsc")
150+
.shadow()
151+
.find(".ui5-dsc-side")
152+
.should("have.attr", "role", customSideRole);
153+
});
83154
});
84155

85156
describe("'sideContentPosition' property", () => {

packages/fiori/src/DynamicSideContent.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ type DynamicSideContentLayoutChangeEventDetail = {
3838
sideContentVisible: boolean,
3939
}
4040

41-
type DynamicSideContentAriaAccessibilityAttributes = Pick<AccessibilityAttributes, "ariaLabel">;
41+
type DynamicSideContentAriaAccessibilityAttributes = Pick<AccessibilityAttributes, "ariaLabel" | "role">;
4242
type DynamicSideContentAccessibilityAttributes = {
4343
mainContent?: DynamicSideContentAriaAccessibilityAttributes,
4444
sideContent?: DynamicSideContentAriaAccessibilityAttributes,
@@ -201,8 +201,13 @@ class DynamicSideContent extends UI5Element {
201201
*
202202
* The accessibilityAttributes object has the following fields:
203203
*
204-
* - **mainContent**: `mainContent.ariaLabel` defines the aria-label of the main content area. Accepts any string.
205-
* - **sideContent**: `sideContent.ariaLabel` defines the aria-label of the side content area. Accepts any string.
204+
* - **mainContent**:
205+
* - **ariaLabel**: defines the aria-label of the main content area. Accepts any string.
206+
* - **role**: defines the role of the main content area. When not set, defaults to `"main"`. Set to `undefined` to remove the role attribute.
207+
*
208+
* - **sideContent**:
209+
* - **ariaLabel**: defines the aria-label of the side content area. Accepts any string.
210+
* - **role**: defines the role of the side content area. When not set, defaults to `"complementary"`. Set to `undefined` to remove the role attribute.
206211
*
207212
* @default {}
208213
* @public
@@ -370,12 +375,19 @@ class DynamicSideContent extends UI5Element {
370375
}
371376

372377
get accInfo(): DynamicSideContentAccessibilityAttributes {
378+
const mainContentAttr = this.accessibilityAttributes.mainContent || {};
379+
const sideContentAttr = this.accessibilityAttributes.sideContent || {};
380+
const hasMainRole = "role" in mainContentAttr;
381+
const hasSideRole = "role" in sideContentAttr;
382+
373383
return {
374384
mainContent: {
375-
ariaLabel: this.accessibilityAttributes.mainContent?.ariaLabel || DynamicSideContent.i18nBundle.getText(DSC_MAIN_ARIA_LABEL),
385+
ariaLabel: mainContentAttr.ariaLabel || DynamicSideContent.i18nBundle.getText(DSC_MAIN_ARIA_LABEL),
386+
role: hasMainRole ? mainContentAttr.role : "main",
376387
},
377388
sideContent: {
378-
ariaLabel: this.accessibilityAttributes.sideContent?.ariaLabel || DynamicSideContent.i18nBundle.getText(DSC_SIDE_ARIA_LABEL),
389+
ariaLabel: sideContentAttr.ariaLabel || DynamicSideContent.i18nBundle.getText(DSC_SIDE_ARIA_LABEL),
390+
role: hasSideRole ? sideContentAttr.role : "complementary",
379391
},
380392
};
381393
}

packages/fiori/src/DynamicSideContentTemplate.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export default function DynamicSideContentTemplate(this: DynamicSideContent) {
2424
function mainContent(this: DynamicSideContent) {
2525
return (
2626
<div
27-
role="main"
27+
role={this.accInfo.mainContent?.role}
2828
aria-label={this.accInfo.mainContent?.ariaLabel}
2929
class={this.classes.main}
3030
style={this.styles.main}
@@ -37,7 +37,7 @@ function mainContent(this: DynamicSideContent) {
3737
function sideContent(this: DynamicSideContent) {
3838
return (
3939
<aside
40-
role="complementary"
40+
role={this.accInfo.sideContent?.role}
4141
aria-label={this.accInfo.sideContent?.ariaLabel}
4242
class={this.classes.side}
4343
style={this.styles.side}

packages/fiori/test/pages/DynamicSideContent.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,11 @@ <h1>Side Content</h1>
134134
dynamicSideContent.accessibilityAttributes = {
135135
mainContent: {
136136
ariaLabel: "Main Content Area",
137+
role: "region",
137138
},
138139
sideContent: {
139140
ariaLabel: "Side Content Area",
141+
role: "note",
140142
}
141143
};
142144
</script>

0 commit comments

Comments
 (0)