mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-08 23:58:13 +08:00
feat(select): add required prop (#30155)
Issue number: resolves internal
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
- Currently, the screen reader do not announce the component as required
when `required={true}`.
## What is the new behavior?
- Added a new `required` prop to be used for accessibility purposes that
adds the `aria-required` attribute to select's inner native button.
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!--
If this introduces a breaking change:
1. Describe the impact and migration path for existing applications
below.
2. Update the BREAKING.md file with the breaking change.
3. Add "BREAKING CHANGE: [...]" to the commit description when merging.
See
https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer
for more information.
-->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
This commit is contained in:
@ -196,6 +196,13 @@ export class Select implements ComponentInterface {
|
||||
*/
|
||||
@Prop({ mutable: true }) value?: any | null;
|
||||
|
||||
/**
|
||||
* If true, screen readers will announce it as a required field. This property
|
||||
* works only for accessibility purposes, it will not prevent the form from
|
||||
* submitting if the value is invalid.
|
||||
*/
|
||||
@Prop() required = false;
|
||||
|
||||
/**
|
||||
* Emitted when the value has changed.
|
||||
*
|
||||
@ -974,7 +981,7 @@ export class Select implements ComponentInterface {
|
||||
}
|
||||
|
||||
private renderListbox() {
|
||||
const { disabled, inputId, isExpanded } = this;
|
||||
const { disabled, inputId, isExpanded, required } = this;
|
||||
|
||||
return (
|
||||
<button
|
||||
@ -983,6 +990,7 @@ export class Select implements ComponentInterface {
|
||||
aria-label={this.ariaLabel}
|
||||
aria-haspopup="dialog"
|
||||
aria-expanded={`${isExpanded}`}
|
||||
aria-required={`${required}`}
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
ref={(focusEl) => (this.focusEl = focusEl)}
|
||||
|
||||
@ -125,3 +125,35 @@ describe('select: slot interactivity', () => {
|
||||
expect(divSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ion-select: required', () => {
|
||||
it('should have a aria-required attribute as true in inner button', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Select],
|
||||
html: `
|
||||
<ion-select required="true"></ion-select>
|
||||
`,
|
||||
});
|
||||
|
||||
const select = page.body.querySelector('ion-select')!;
|
||||
|
||||
const nativeButton = select.shadowRoot!.querySelector('button')!;
|
||||
|
||||
expect(nativeButton.getAttribute('aria-required')).toBe('true');
|
||||
});
|
||||
|
||||
it('should not have a aria-required attribute as false in inner button', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Select],
|
||||
html: `
|
||||
<ion-select required="false"></ion-select>
|
||||
`,
|
||||
});
|
||||
|
||||
const select = page.body.querySelector('ion-select')!;
|
||||
|
||||
const nativeButton = select.shadowRoot!.querySelector('button')!;
|
||||
|
||||
expect(nativeButton.getAttribute('aria-required')).toBe('false');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user