diff --git a/core/src/components/datetime/datetime.tsx b/core/src/components/datetime/datetime.tsx index eb6a1e9d09..e2a2f3ba35 100644 --- a/core/src/components/datetime/datetime.tsx +++ b/core/src/components/datetime/datetime.tsx @@ -641,7 +641,7 @@ export class Datetime implements ComponentInterface { aria-disabled={disabled ? 'true' : null} aria-expanded={`${isExpanded}`} aria-haspopup="true" - aria-labelledby={labelId} + aria-labelledby={label ? labelId : null} class={{ [mode]: true, 'datetime-disabled': disabled, diff --git a/core/src/components/datetime/test/a11y/datetime.spec.ts b/core/src/components/datetime/test/a11y/datetime.spec.ts new file mode 100644 index 0000000000..2007e77ce3 --- /dev/null +++ b/core/src/components/datetime/test/a11y/datetime.spec.ts @@ -0,0 +1,30 @@ +import { newSpecPage } from '@stencil/core/testing'; +import { Datetime } from '../../datetime'; +import { Item } from '../../../item/item'; +import { Label } from '../../../label/label'; + +describe('Datetime a11y', () => { + it('does not set a default aria-labelledby when there is not a neighboring ion-label', async () => { + const page = await newSpecPage({ + components: [Datetime, Item, Label], + html: `` + }) + + const ariaLabelledBy = page.root.getAttribute('aria-labelledby'); + expect(ariaLabelledBy).toBe(null); + }); + + it('set a default aria-labelledby when a neighboring ion-label exists', async () => { + const page = await newSpecPage({ + components: [Datetime, Item, Label], + html: ` + A11y Test + + ` + }) + + const label = page.body.querySelector('ion-label'); + const ariaLabelledBy = page.body.querySelector('ion-datetime').getAttribute('aria-labelledby'); + expect(ariaLabelledBy).toBe(label.id); + }); +}); diff --git a/core/src/components/datetime/test/standalone/index.html b/core/src/components/datetime/test/standalone/index.html index c56a40a2a7..847c6beedf 100644 --- a/core/src/components/datetime/test/standalone/index.html +++ b/core/src/components/datetime/test/standalone/index.html @@ -12,6 +12,6 @@ - + diff --git a/core/src/components/input/input.tsx b/core/src/components/input/input.tsx index b749e719b5..5d2fa386b4 100644 --- a/core/src/components/input/input.tsx +++ b/core/src/components/input/input.tsx @@ -408,7 +408,7 @@ export class Input implements ComponentInterface { this.nativeInput = input} - aria-labelledby={labelId} + aria-labelledby={label ? labelId : null} disabled={this.disabled} accept={this.accept} autoCapitalize={this.autocapitalize} diff --git a/core/src/components/input/test/a11y/input.spec.ts b/core/src/components/input/test/a11y/input.spec.ts new file mode 100644 index 0000000000..97c5708fe1 --- /dev/null +++ b/core/src/components/input/test/a11y/input.spec.ts @@ -0,0 +1,30 @@ +import { newSpecPage } from '@stencil/core/testing'; +import { Input } from '../../input'; +import { Item } from '../../../item/item'; +import { Label } from '../../../label/label'; + +describe('Input a11y', () => { + it('does not set a default aria-labelledby when there is not a neighboring ion-label', async () => { + const page = await newSpecPage({ + components: [Input, Item, Label], + html: `` + }) + + const ariaLabelledBy = page.body.querySelector('ion-input > input').getAttribute('aria-labelledby'); + expect(ariaLabelledBy).toBe(null); + }); + + it('set a default aria-labelledby when a neighboring ion-label exists', async () => { + const page = await newSpecPage({ + components: [Input, Item, Label], + html: ` + A11y Test + + ` + }) + + const label = page.body.querySelector('ion-label'); + const ariaLabelledBy = page.body.querySelector('ion-input > input').getAttribute('aria-labelledby'); + expect(ariaLabelledBy).toBe(label.id); + }); +}); diff --git a/core/src/components/input/test/attributes/index.html b/core/src/components/input/test/attributes/index.html index fff4ea9f8c..fbf0400967 100644 --- a/core/src/components/input/test/attributes/index.html +++ b/core/src/components/input/test/attributes/index.html @@ -46,6 +46,10 @@ + + + + Number Test  @@ -59,6 +63,10 @@ Default Test  + + No Label Test  + + @@ -74,6 +82,9 @@ var defaultInput = checkInput('input3'); updateResult(defaultInput, 'defaultInputResult'); + var noLabelInput = checkInput('input4'); + updateResult(noLabelInput, 'noLabelInputResult'); + // Update results of input function updateResult(result, resultId) { var resultEl = document.getElementById(resultId); @@ -122,6 +133,14 @@ readonly: undefined, disabled: undefined }); + } else if (id === 'input4') { + return testAttributes(el, inputEl, { + id: 'input4', + type: undefined, + readonly: undefined, + disabled: undefined, + 'aria-label': 'input4' + }); } return false; } diff --git a/core/src/components/textarea/test/a11y/textarea.spec.ts b/core/src/components/textarea/test/a11y/textarea.spec.ts new file mode 100644 index 0000000000..9a69f5ef18 --- /dev/null +++ b/core/src/components/textarea/test/a11y/textarea.spec.ts @@ -0,0 +1,30 @@ +import { newSpecPage } from '@stencil/core/testing'; +import { Textarea } from '../../textarea'; +import { Item } from '../../../item/item'; +import { Label } from '../../../label/label'; + +describe('Textarea a11y', () => { + it('does not set a default aria-labelledby when there is not a neighboring ion-label', async () => { + const page = await newSpecPage({ + components: [Textarea, Item, Label], + html: `` + }) + + const ariaLabelledBy = page.body.querySelector('ion-textarea textarea').getAttribute('aria-labelledby'); + expect(ariaLabelledBy).toBe(null); + }); + + it('set a default aria-labelledby when a neighboring ion-label exists', async () => { + const page = await newSpecPage({ + components: [Textarea, Item, Label], + html: ` + A11y Test + + ` + }) + + const label = page.body.querySelector('ion-label'); + const ariaLabelledBy = page.body.querySelector('ion-textarea textarea').getAttribute('aria-labelledby'); + expect(ariaLabelledBy).toBe(label.id); + }); +}); diff --git a/core/src/components/textarea/textarea.tsx b/core/src/components/textarea/textarea.tsx index 960e7a408a..2105a2f9ac 100644 --- a/core/src/components/textarea/textarea.tsx +++ b/core/src/components/textarea/textarea.tsx @@ -363,7 +363,7 @@ export class Textarea implements ComponentInterface { >