Skip to content
Closed
1 change: 1 addition & 0 deletions packages/volto/news/8313.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improved screen reader support in SelectWidget and ArrayWidget: added dynamic aria-label with field name and current value, keyboard navigation for selected chips, and hidden the clear button on required fields. @Wagner3UB
Comment thread
Wagner3UB marked this conversation as resolved.
Outdated
16 changes: 13 additions & 3 deletions packages/volto/src/components/manage/Widgets/ArrayWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,18 @@ class ArrayWidget extends Component {
>
<SelectComponent
menuShouldScrollIntoView={false}
id={`field-${this.props.id}`}
aria-labelledby={`fieldset-${this.props.fieldSet}-field-label-${this.props.id}`}
id={`select-container-${this.props.id}`}
inputId={`field-${this.props.id}`}
fieldTitle={this.props.title}
aria-label={
this.props.title
? `${this.props.title}: ${
selectedOption?.length > 0
? selectedOption.map((v) => v.label).join(', ')
: this.props.intl.formatMessage(messages.no_value)
}`
: undefined
}
key={this.props.id}
isDisabled={this.props.disabled || this.props.isDisabled}
className="react-select-container"
Expand Down Expand Up @@ -400,7 +410,7 @@ class ArrayWidget extends Component {
)
)
}
isClearable
isClearable={!this.props.required}
isMulti
/>
</SortableContext>
Expand Down
12 changes: 11 additions & 1 deletion packages/volto/src/components/manage/Widgets/SelectStyling.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ export const SortableMultiValue = injectLazyLibs([
}}
{...attributes}
{...listeners}
tabIndex={-1}
aria-label={`${props.selectProps.fieldTitle || ''}: ${props.data.label}`}
onKeyDown={(e) => {
if (e.key === 'Delete' || e.key === 'Backspace' || e.key === 'Enter') {
e.preventDefault();
props.removeProps?.onClick?.(e);
}
}}
>
<MultiValue
{...props}
Expand All @@ -68,7 +76,7 @@ export const MultiValueContainer = injectLazyLibs('reactSelect')((props) => {
<Popup
content={props.data.label}
trigger={
<div {...props.innerProps}>
<div ref={props.innerProps?.ref}>
<MultiValueContainer {...props} />
</div>
}
Expand All @@ -83,6 +91,8 @@ export const MultiValueRemove = injectLazyLibs(['reactSelect'])((props) => {
{...props}
innerProps={{
...props.innerProps,
role: 'button',
tabIndex: -1,
onPointerDown: (e) => e.stopPropagation(),
}}
/>
Expand Down
18 changes: 15 additions & 3 deletions packages/volto/src/components/manage/Widgets/SelectWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,22 @@ class SelectWidget extends Component {
return (
<FormFieldWrapper {...this.props}>
<Select
id={`field-${id}`}
id={`select-container-${id}`}
inputId={`field-${id}`}
fieldTitle={this.props.title}
key={choices}
name={id}
aria-labelledby={`fieldset-${this.props.fieldSet}-field-label-${id}`}
aria-label={
this.props.title
? `${this.props.title}: ${
normalizedValue
? Array.isArray(normalizedValue)
? normalizedValue.map((v) => v.label).join(', ')
: normalizedValue.label
: intl.formatMessage(messages.no_value)
}`
: undefined
}
menuShouldScrollIntoView={false}
isDisabled={disabled}
isSearchable={true}
Expand Down Expand Up @@ -304,7 +316,7 @@ class SelectWidget extends Component {
: undefined,
);
}}
isClearable={this.props.isClearable}
isClearable={!this.props.required && this.props.isClearable}
/>
</FormFieldWrapper>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ exports[`No 'No value' option when default value is 0 1`] = `
>
<div
class="react-select-container css-2b097c-container"
id="field-my-field"
id="select-container-my-field"
>
<span
aria-atomic="false"
Expand Down Expand Up @@ -67,11 +67,11 @@ exports[`No 'No value' option when default value is 0 1`] = `
>
<input
aria-autocomplete="list"
aria-labelledby="fieldset-default-field-label-my-field"
aria-label="My field: No value"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
id="react-select-3-input"
id="field-my-field"
spellcheck="false"
style="box-sizing: content-box; width: 2px; background: 0px center; border: 0px; font-size: inherit; opacity: 1; outline: 0px; padding: 0px; color: inherit;"
tabindex="0"
Expand Down Expand Up @@ -228,7 +228,7 @@ exports[`renders an array widget component 1`] = `
>
<div
className="react-select-container css-2b097c-container"
id="field-my-field"
id="select-container-my-field"
onKeyDown={[Function]}
>
<span
Expand Down Expand Up @@ -263,12 +263,12 @@ exports[`renders an array widget component 1`] = `
>
<input
aria-autocomplete="list"
aria-labelledby="fieldset-default-field-label-my-field"
aria-label="My field: No value"
autoCapitalize="none"
autoComplete="off"
autoCorrect="off"
disabled={false}
id="react-select-2-input"
id="field-my-field"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ exports[`No 'No value' option when default value is 0 1`] = `
>
<div
class="react-select-container css-2b097c-container"
id="field-my-field"
id="select-container-my-field"
>
<span
aria-atomic="false"
Expand Down Expand Up @@ -67,11 +67,11 @@ exports[`No 'No value' option when default value is 0 1`] = `
>
<input
aria-autocomplete="list"
aria-labelledby="fieldset-default-field-label-my-field"
aria-label="My field: None"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
id="react-select-3-input"
id="field-my-field"
spellcheck="false"
style="box-sizing: content-box; width: 2px; background: 0px center; border: 0px; font-size: inherit; opacity: 1; outline: 0px; padding: 0px; color: inherit;"
tabindex="0"
Expand Down Expand Up @@ -233,7 +233,7 @@ exports[`renders a select widget component 1`] = `
>
<div
class="react-select-container css-2b097c-container"
id="field-my-field"
id="select-container-my-field"
>
<span
aria-atomic="false"
Expand Down Expand Up @@ -261,11 +261,11 @@ exports[`renders a select widget component 1`] = `
>
<input
aria-autocomplete="list"
aria-labelledby="fieldset-default-field-label-my-field"
aria-label="My field: No value"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
id="react-select-2-input"
id="field-my-field"
spellcheck="false"
style="box-sizing: content-box; width: 2px; background: 0px center; border: 0px; font-size: inherit; opacity: 1; outline: 0px; padding: 0px; color: inherit;"
tabindex="0"
Expand Down
Loading