diff --git a/.changeset/late-baboons-dream.md b/.changeset/late-baboons-dream.md new file mode 100644 index 0000000000..da2eb605da --- /dev/null +++ b/.changeset/late-baboons-dream.md @@ -0,0 +1,5 @@ +--- +'@sebgroup/green-core': patch +--- + +**Datepicker and Dropdown:** minor a11y improvements diff --git a/libs/core/src/components/datepicker/datepicker.styles.ts b/libs/core/src/components/datepicker/datepicker.styles.ts index 217ee6f0b4..0035270d9e 100644 --- a/libs/core/src/components/datepicker/datepicker.styles.ts +++ b/libs/core/src/components/datepicker/datepicker.styles.ts @@ -38,7 +38,7 @@ export const styles = css` line-height: 1; text-align: center; - &:focus-visible { + &:focus { background-color: var(--gds-color-l3-background-primary); color: var(--gds-color-l3-content-primary); } diff --git a/libs/core/src/components/datepicker/datepicker.test.ts b/libs/core/src/components/datepicker/datepicker.test.ts index 54a53a5f6e..a0a05b8440 100644 --- a/libs/core/src/components/datepicker/datepicker.test.ts +++ b/libs/core/src/components/datepicker/datepicker.test.ts @@ -576,4 +576,30 @@ describe('', () => { await expect(yearDropdown.value).to.equal('2014') }) }) + + describe('Accessibility', () => { + it('should pass axe smoketest', async () => { + const el = await fixture( + html``, + ) + await el.updateComplete + await expect(el).to.be.accessible({ + ignoredRules: ['color-contrast'], + }) + }) + + it('should have a label for #spinner-0', async () => { + const el = await fixture( + html``, + ) + const label = + el.shadowRoot!.querySelector('[for="spinner-0"]')! + expect(label).to.exist + }) + }) }) diff --git a/libs/core/src/components/datepicker/datepicker.ts b/libs/core/src/components/datepicker/datepicker.ts index 45aec7b31a..ebffc40606 100644 --- a/libs/core/src/components/datepicker/datepicker.ts +++ b/libs/core/src/components/datepicker/datepicker.ts @@ -1,7 +1,6 @@ import { localized, msg } from '@lit/localize' import { nothing } from 'lit' import { property, query, queryAll, queryAsync, state } from 'lit/decorators.js' -import { classMap } from 'lit/directives/class-map.js' import { join } from 'lit/directives/join.js' import { map } from 'lit/directives/map.js' import { repeat } from 'lit/directives/repeat.js' @@ -158,7 +157,7 @@ export class GdsDatepicker extends GdsFormControlElement { * Get a string representation of the currently displayed value in the input field. The formatting will match the dateformat attribute. */ get displayValue() { - return this._elInput.innerText.replace(/\s+/g, '') + return this._elField.innerText.replace(/\s+/g, '') } /** @@ -191,14 +190,14 @@ export class GdsDatepicker extends GdsFormControlElement { @queryAsync('#calendar-button') private _elTrigger!: Promise - @queryAsync('#date-picker') - private _elField!: Promise + @queryAsync('#field') + private _elFieldAsync!: Promise @queryAll('[role=spinbutton]') private _elSpinners!: NodeListOf - @query('.input') - private _elInput!: HTMLDivElement + @query('#field') + private _elField!: HTMLDivElement #valueOnOpen?: Date @@ -210,7 +209,7 @@ export class GdsDatepicker extends GdsFormControlElement { render() { return html` - + ${when( this.supportingText.length > 0, () => @@ -219,11 +218,16 @@ export class GdsDatepicker extends GdsFormControlElement { `, )} - + { @click=${this.#handleFieldClick} @copy=${this.#handleClipboardCopy} @paste=${this.#handleClipboardPaste} - id="date-picker" + id="field" >
${join( @@ -241,13 +245,14 @@ export class GdsDatepicker extends GdsFormControlElement { (f, i) => html` { // Wrapped in a slot for backwards compatibility with the deprecated message slot // Remove for 2.0 release () => html` - + @@ -300,7 +305,7 @@ export class GdsDatepicker extends GdsFormControlElement { { } #handleClipboardCopy = (e: ClipboardEvent) => { - this._elField.then((field) => { + this._elFieldAsync.then((field) => { if (e.currentTarget !== field) return e.preventDefault() e.clipboardData?.setData('text/plain', this.displayValue) @@ -566,7 +571,7 @@ export class GdsDatepicker extends GdsFormControlElement { } #handleClipboardPaste = (e: ClipboardEvent) => { - this._elField.then((field: HTMLElement) => { + this._elFieldAsync.then((field: HTMLElement) => { if (e.currentTarget !== field) return e.preventDefault() const pasted = e.clipboardData?.getData('text/plain') diff --git a/libs/core/src/components/dropdown/dropdown.test.ts b/libs/core/src/components/dropdown/dropdown.test.ts index acae210a11..00932d45a1 100644 --- a/libs/core/src/components/dropdown/dropdown.test.ts +++ b/libs/core/src/components/dropdown/dropdown.test.ts @@ -702,3 +702,30 @@ describe('', () => { await expect(el.displayValue).to.equal('Select values') }) }) + +describe(' accessibility', () => { + it('pass axe smoketest', async () => { + const el = await fixture(html` + + Option 1 + Option 2 + Option 3 + + `) + await expect(el).to.be.accessible() + }) + + it('should have a label for the trigger', async () => { + const el = await fixture(html` + + Option 1 + Option 2 + Option 3 + + `) + const trigger = el.shadowRoot!.querySelector('button')! + const label = el.shadowRoot!.querySelector('label')! + + await expect(label.getAttribute('for')).to.equal(trigger.id) + }) +}) diff --git a/libs/core/src/components/dropdown/dropdown.ts b/libs/core/src/components/dropdown/dropdown.ts index c1fb8f7184..7c5106a9ca 100644 --- a/libs/core/src/components/dropdown/dropdown.ts +++ b/libs/core/src/components/dropdown/dropdown.ts @@ -237,7 +237,7 @@ export class GdsDropdown !this.hideLabel, () => html` - + ${when( this.supportingText.length > 0, () => @@ -246,11 +246,12 @@ export class GdsDropdown `, )} - + `, )} @@ -267,17 +268,24 @@ export class GdsDropdown .size=${this.size} .disabled=${this.disabled} .invalid=${this.invalid} - aria-haspopup="listbox" slot="trigger" - role="combobox" - aria-owns="listbox" - aria-controls="listbox" - aria-expanded="${this.open}" - aria-label="${this.label}" id="field" > -