Skip to content

Commit 9ef1e18

Browse files
sirrah-tamdaneah
andauthored
A11y revamp: Pharos buttons (non-breaking change) (#628)
* docs: add @sirrah-tam as a contributor * feat(button): add a11y naming convention for aria * feat(button): add aria-description support * chore: add changset * Update packages/pharos/src/components/button/pharos-button.ts Co-authored-by: Dane Hillard <[email protected]> * Update packages/pharos/src/components/button/pharos-button.ts Co-authored-by: Dane Hillard <[email protected]> * feat(button): move property deprecated flag * fix(button): remove ts-ignore after lit upgrade * feat(button): add a11y state typing * fix: add TODO for future reference Co-authored-by: Dane Hillard <[email protected]> * fix(a11y attributes): update AriaHiddenState name --------- Co-authored-by: Dane Hillard <[email protected]>
1 parent 3ad3fd6 commit 9ef1e18

File tree

6 files changed

+88
-20
lines changed

6 files changed

+88
-20
lines changed

.changeset/large-frogs-smile.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@ithaka/pharos': minor
3+
---
4+
5+
Update PharosButton to use a11y naming convention and include wider ARIA support

packages/pharos/src/components/button/pharos-button.ts

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@ export type ButtonType = 'button' | 'submit' | 'reset';
1717

1818
export type ButtonVariant = 'primary' | 'secondary' | 'subtle' | 'overlay';
1919

20-
// undefined means no state has been expressed at all and won't render; 'undefined' is an explicit state
21-
export type PressedState = 'false' | 'true' | 'mixed' | 'undefined' | undefined;
22-
2320
const TYPES = ['button', 'submit', 'reset'] as ButtonType[];
2421

2522
const VARIANTS = ['primary', 'secondary', 'subtle', 'overlay'] as ButtonVariant[];
@@ -112,12 +109,41 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement))
112109
public large = false;
113110

114111
/**
112+
* @deprecated
115113
* Indicates the aria label to apply to the button.
116114
* @attr label
117115
*/
118116
@property({ type: String, reflect: true })
119117
public label?: string;
120118

119+
/**
120+
* Indicates the aria label to apply to the button.
121+
* @attr a11y-label
122+
*/
123+
@property({ type: String, reflect: true, attribute: 'a11y-label' })
124+
public a11yLabel?: string;
125+
126+
/**
127+
* Indicates the aria description to apply to the button.
128+
* @attr a11y-description
129+
*/
130+
@property({ type: String, reflect: true, attribute: 'a11y-description' })
131+
public a11yDescription?: string;
132+
133+
/**
134+
* Indicates the aria expanded state to apply to the button.
135+
* @attr a11y-expanded
136+
*/
137+
@property({ type: String, reflect: true, attribute: 'a11y-expanded' })
138+
public a11yExpanded: AriaExpandedState = undefined;
139+
140+
/**
141+
* Indicates the aria expanded state to apply to the button.
142+
* @attr a11y-haspopup
143+
*/
144+
@property({ type: String, reflect: true, attribute: 'a11y-haspopup' })
145+
public a11yHaspopup: AriaPopupState = undefined;
146+
121147
/**
122148
* Indicates the button's width should match its container.
123149
* @attr full-width
@@ -140,11 +166,19 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement))
140166
public value?: string;
141167

142168
/**
169+
* @deprecated
143170
* Indicates this button is a toggle button and whether it is pressed or not.
144171
* @attr value
145172
*/
146173
@property({ type: String, reflect: true })
147-
public pressed: PressedState = undefined;
174+
public pressed: AriaPressedState = undefined;
175+
176+
/**
177+
* Indicates this button is a toggle button and whether it is pressed or not.
178+
* @attr value
179+
*/
180+
@property({ type: String, reflect: true, attribute: 'a11y-pressed' })
181+
public a11yPressed: AriaPressedState = undefined;
148182

149183
@query('#button-element')
150184
private _button!: HTMLButtonElement | HTMLAnchorElement;
@@ -178,6 +212,14 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement))
178212
`${this.variant} is not a valid variant. Valid variants are: ${VARIANTS.join(', ')}`
179213
);
180214
}
215+
216+
if (this.label) {
217+
console.warn("The 'label' attribute is deprecated. Use 'a11y-label' instead.");
218+
}
219+
220+
if (this.pressed) {
221+
console.warn("The 'pressed' attribute is deprecated. Use 'a11y-pressed' instead.");
222+
}
181223
}
182224

183225
override connectedCallback(): void {
@@ -243,6 +285,10 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement))
243285
}
244286

245287
protected override render(): TemplateResult {
288+
// TODO: Remove in future release once sufficient time elapsed to update naming convention
289+
const a11yLabel = this.a11yLabel ?? this.label;
290+
const a11yPressed = this.a11yPressed ?? this.pressed;
291+
246292
return this.href
247293
? html`
248294
<a
@@ -254,8 +300,11 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement))
254300
ping=${ifDefined(this.ping)}
255301
rel=${ifDefined(this.rel)}
256302
target=${ifDefined(this.target)}
257-
aria-label=${ifDefined(this.label)}
258-
aria-pressed=${ifDefined(this.pressed)}
303+
aria-label=${ifDefined(a11yLabel)}
304+
aria-description=${ifDefined(this.a11yDescription)}
305+
aria-pressed=${ifDefined(a11yPressed)}
306+
aria-expanded=${ifDefined(this.a11yExpanded)}
307+
aria-haspopup=${ifDefined(this.a11yHaspopup)}
259308
@keyup=${this._handleKeyup}
260309
>
261310
${this.buttonContent}
@@ -269,8 +318,11 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement))
269318
?autofocus=${this.autofocus}
270319
?disabled=${this.disabled}
271320
type="${ifDefined(this.type)}"
272-
aria-label=${ifDefined(this.label)}
273-
aria-pressed=${ifDefined(this.pressed)}
321+
aria-label=${ifDefined(a11yLabel)}
322+
aria-description=${ifDefined(this.a11yDescription)}
323+
aria-pressed=${ifDefined(a11yPressed)}
324+
aria-expanded=${ifDefined(this.a11yExpanded)}
325+
aria-haspopup=${ifDefined(this.a11yHaspopup)}
274326
>
275327
${this.buttonContent}
276328
</button>

packages/pharos/src/components/sidenav/pharos-sidenav-button.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { PharosButton } from '../button/pharos-button';
44
import type { PharosSidenav } from './pharos-sidenav';
55

66
import type { LinkTarget } from '../base/anchor-element';
7-
import type { ButtonType, IconName, ButtonVariant, PressedState } from '../button/pharos-button';
8-
export type { LinkTarget, ButtonType, IconName, ButtonVariant, PressedState };
7+
import type { ButtonType, IconName, ButtonVariant } from '../button/pharos-button';
8+
export type { LinkTarget, ButtonType, IconName, ButtonVariant };
99

1010
/**
1111
* Pharos sidenav button component.

packages/pharos/src/components/toast/pharos-toast-button.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { toastButtonStyles } from './pharos-toast-button.css';
33
import { PharosButton } from '../button/pharos-button';
44

55
import type { LinkTarget } from '../base/anchor-element';
6-
import type { ButtonType, IconName, ButtonVariant, PressedState } from '../button/pharos-button';
6+
import type { ButtonType, IconName, ButtonVariant } from '../button/pharos-button';
77

8-
export type { LinkTarget, ButtonType, IconName, ButtonVariant, PressedState };
8+
export type { LinkTarget, ButtonType, IconName, ButtonVariant };
99

1010
/**
1111
* Pharos toast button component.

packages/pharos/src/components/toggle-button-group/pharos-toggle-button.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,8 @@ import type { CSSResultArray, PropertyValues } from 'lit';
33
import { toggleButtonStyles } from './pharos-toggle-button.css';
44
import { PharosButton } from '../button/pharos-button';
55

6-
import type {
7-
ButtonType,
8-
LinkTarget,
9-
IconName,
10-
ButtonVariant,
11-
PressedState,
12-
} from '../button/pharos-button';
13-
export type { ButtonType, LinkTarget, IconName, ButtonVariant, PressedState };
6+
import type { ButtonType, LinkTarget, IconName, ButtonVariant } from '../button/pharos-button';
7+
export type { ButtonType, LinkTarget, IconName, ButtonVariant };
148

159
/**
1610
* Pharos toggle button component.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export {};
2+
3+
declare global {
4+
type AriaHiddenState = 'false' | 'true' | 'undefined' | undefined;
5+
type AriaPressedState = 'false' | 'true' | 'mixed' | 'undefined' | undefined;
6+
type AriaExpandedState = 'false' | 'true' | 'undefined' | undefined;
7+
type AriaDisabledState = 'false' | 'true' | undefined;
8+
type AriaPopupState =
9+
| 'false'
10+
| 'true'
11+
| 'menu'
12+
| 'tree'
13+
| 'grid'
14+
| 'listbox'
15+
| 'dialog'
16+
| undefined;
17+
}

0 commit comments

Comments
 (0)