Skip to content

Commit 2a45088

Browse files
authored
fix(switch): add static accessible label (#3094)
* fix(switch): add static accessible label Rename `label` property to `accessibleLabel` (attribute: `accessible-label`) for consistency. Wire it to set `ariaLabel` on element internals for a proper static accessible name. Closes #2754 Assisted-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: changeset * fix(switch): keep label as deprecated, add accessible-label Keep the existing `label` property as deprecated and fall back to it when `accessible-label` is not set. JSDoc advises updating the accessible label based on checked state. Assisted-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6b3031b commit 2a45088

4 files changed

Lines changed: 37 additions & 2 deletions

File tree

.changeset/fix-switch-a11y.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@patternfly/elements": patch
3+
---
4+
5+
`<pf-switch>`: the switch now has a proper static accessible label
6+
independent of its on/off state text.

elements/pf-switch/demo/without-label.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<form>
33
<fieldset>
44
<legend>Without label</legend>
5-
<pf-switch checked></pf-switch>
5+
<pf-switch accessible-label="Toggle option" checked></pf-switch>
66
</fieldset>
77
</form>
88
</section>

elements/pf-switch/pf-switch.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,16 @@ export class PfSwitch extends LitElement {
2424

2525
#internals = InternalsController.of(this, { role: 'switch' });
2626

27-
/** Accessible label text for the switch */
27+
/** @deprecated use `accessible-label` instead */
2828
@property({ reflect: true }) label?: string;
2929

30+
/**
31+
* Accessible label for the switch when there is no associated `<label>` element.
32+
* Update this value based on the checked state to communicate the meaning of
33+
* each state to assistive technology users, e.g. "Wi-Fi on" / "Wi-Fi off".
34+
*/
35+
@property({ reflect: true, attribute: 'accessible-label' }) accessibleLabel?: string;
36+
3037
/** Flag to show if the switch has a check icon. */
3138
@property({ reflect: true, type: Boolean, attribute: 'show-check-icon' }) showCheckIcon = false;
3239

@@ -57,6 +64,7 @@ export class PfSwitch extends LitElement {
5764
override willUpdate(): void {
5865
this.#internals.ariaChecked = String(!!this.checked);
5966
this.#internals.ariaDisabled = String(!!this.disabled);
67+
this.#internals.ariaLabel = this.accessibleLabel || this.label || null;
6068
}
6169

6270
override render(): TemplateResult<1> {

elements/pf-switch/test/pf-switch.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,27 @@ describe('<pf-switch>', function() {
4343
});
4444
});
4545

46+
describe('with accessible-label attribute', function() {
47+
let element: PfSwitch;
48+
let snapshot: A11yTreeSnapshot;
49+
beforeEach(async function() {
50+
element = await createFixture<PfSwitch>(html`
51+
<pf-switch accessible-label="Dark Mode"></pf-switch>
52+
`);
53+
snapshot = await a11ySnapshot({ selector: 'pf-switch' });
54+
});
55+
it('has an accessible name from accessible-label', function() {
56+
expect(snapshot.name).to.equal('Dark Mode');
57+
});
58+
it('keeps the same accessible name regardless of checked state', async function() {
59+
element.click();
60+
await element.updateComplete;
61+
await nextFrame();
62+
snapshot = await a11ySnapshot({ selector: 'pf-switch' });
63+
expect(snapshot.name).to.equal('Dark Mode');
64+
});
65+
});
66+
4667
describe('with labels for on and off state', function() {
4768
let element: PfSwitch;
4869
let snapshot: A11yTreeSnapshot;

0 commit comments

Comments
 (0)