Skip to content

Commit 9fd0aea

Browse files
[8.19] [A11y] Add labels to control inputs (#221639) (#226251)
# Backport This will backport the following commits from `main` to `8.19`: - [[A11y] Add labels to control inputs (#221639)](#221639) <!--- Backport version: 10.0.1 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Catherine Liu","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-06-26T21:54:03Z","message":"[A11y] Add labels to control inputs (#221639)\n\n## Summary\n\nCloses #183202.\nCloses #220687.\n\nThis adds aria-labels to the number fields on the range slider control.\n\n<img width=\"704\" alt=\"Screenshot 2025-05-27 at 8 10 38 AM\"\nsrc=\"https://github.com/user-attachments/assets/ffeb1b98-6765-41ab-abd3-bff2ce176cda\"\n/>\n\n<img width=\"413\" alt=\"Screenshot 2025-05-27 at 8 04 59 AM\"\nsrc=\"https://github.com/user-attachments/assets/e899b1f9-6290-463f-9213-2e0a456fa677\"\n/>\n\nThis also adds an aria-label to the search filter at the top of the\noptions list popover.\n\n<img width=\"2559\" alt=\"Screenshot 2025-06-02 at 7 23 53 AM\"\nsrc=\"https://github.com/user-attachments/assets/47e870dc-55c2-40bd-b461-a16022691810\"\n/>\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n- [ ] Any text added follows [EUI's writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\nsentence case text and includes [i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n- [ ]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas added for features that require explanation or tutorials\n- [ ] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [ ] If a plugin configuration key changed, check if it needs to be\nallowlisted in the cloud and added to the [docker\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\n- [ ] This was checked for breaking HTTP API changes, and any breaking\nchanges have been approved by the breaking-change committee. The\n`release_note:breaking` label should be applied in these situations.\n- [ ] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n- [ ] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n### Identify risks\n\nDoes this PR introduce any risks? For example, consider risks like hard\nto test bugs, performance regression, potential of data loss.\n\nDescribe the risk, its severity, and mitigation for each identified\nrisk. Invite stakeholders and evaluate how to proceed before merging.\n\n- [ ] [See some risk\nexamples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx)\n- [ ] ...\n\n---------\n\nCo-authored-by: Marta Bondyra <[email protected]>","sha":"f7dad16597d9d29b312b877a4cb8c9e9bdf4f5ac","branchLabelMapping":{"^v9.1.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Feature:Dashboard","Team:Presentation","loe:small","release_note:skip","impact:high","backport missing","ci:cloud-deploy","backport:version","a11y","v9.1.0","v8.19.0","v9.0.1"],"title":"[A11y] Add labels to control inputs","number":221639,"url":"https://github.com/elastic/kibana/pull/221639","mergeCommit":{"message":"[A11y] Add labels to control inputs (#221639)\n\n## Summary\n\nCloses #183202.\nCloses #220687.\n\nThis adds aria-labels to the number fields on the range slider control.\n\n<img width=\"704\" alt=\"Screenshot 2025-05-27 at 8 10 38 AM\"\nsrc=\"https://github.com/user-attachments/assets/ffeb1b98-6765-41ab-abd3-bff2ce176cda\"\n/>\n\n<img width=\"413\" alt=\"Screenshot 2025-05-27 at 8 04 59 AM\"\nsrc=\"https://github.com/user-attachments/assets/e899b1f9-6290-463f-9213-2e0a456fa677\"\n/>\n\nThis also adds an aria-label to the search filter at the top of the\noptions list popover.\n\n<img width=\"2559\" alt=\"Screenshot 2025-06-02 at 7 23 53 AM\"\nsrc=\"https://github.com/user-attachments/assets/47e870dc-55c2-40bd-b461-a16022691810\"\n/>\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n- [ ] Any text added follows [EUI's writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\nsentence case text and includes [i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n- [ ]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas added for features that require explanation or tutorials\n- [ ] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [ ] If a plugin configuration key changed, check if it needs to be\nallowlisted in the cloud and added to the [docker\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\n- [ ] This was checked for breaking HTTP API changes, and any breaking\nchanges have been approved by the breaking-change committee. The\n`release_note:breaking` label should be applied in these situations.\n- [ ] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n- [ ] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n### Identify risks\n\nDoes this PR introduce any risks? For example, consider risks like hard\nto test bugs, performance regression, potential of data loss.\n\nDescribe the risk, its severity, and mitigation for each identified\nrisk. Invite stakeholders and evaluate how to proceed before merging.\n\n- [ ] [See some risk\nexamples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx)\n- [ ] ...\n\n---------\n\nCo-authored-by: Marta Bondyra <[email protected]>","sha":"f7dad16597d9d29b312b877a4cb8c9e9bdf4f5ac"}},"sourceBranch":"main","suggestedTargetBranches":["8.19","9.0"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/221639","number":221639,"mergeCommit":{"message":"[A11y] Add labels to control inputs (#221639)\n\n## Summary\n\nCloses #183202.\nCloses #220687.\n\nThis adds aria-labels to the number fields on the range slider control.\n\n<img width=\"704\" alt=\"Screenshot 2025-05-27 at 8 10 38 AM\"\nsrc=\"https://github.com/user-attachments/assets/ffeb1b98-6765-41ab-abd3-bff2ce176cda\"\n/>\n\n<img width=\"413\" alt=\"Screenshot 2025-05-27 at 8 04 59 AM\"\nsrc=\"https://github.com/user-attachments/assets/e899b1f9-6290-463f-9213-2e0a456fa677\"\n/>\n\nThis also adds an aria-label to the search filter at the top of the\noptions list popover.\n\n<img width=\"2559\" alt=\"Screenshot 2025-06-02 at 7 23 53 AM\"\nsrc=\"https://github.com/user-attachments/assets/47e870dc-55c2-40bd-b461-a16022691810\"\n/>\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n- [ ] Any text added follows [EUI's writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\nsentence case text and includes [i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n- [ ]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas added for features that require explanation or tutorials\n- [ ] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [ ] If a plugin configuration key changed, check if it needs to be\nallowlisted in the cloud and added to the [docker\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\n- [ ] This was checked for breaking HTTP API changes, and any breaking\nchanges have been approved by the breaking-change committee. The\n`release_note:breaking` label should be applied in these situations.\n- [ ] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n- [ ] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n### Identify risks\n\nDoes this PR introduce any risks? For example, consider risks like hard\nto test bugs, performance regression, potential of data loss.\n\nDescribe the risk, its severity, and mitigation for each identified\nrisk. Invite stakeholders and evaluate how to proceed before merging.\n\n- [ ] [See some risk\nexamples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx)\n- [ ] ...\n\n---------\n\nCo-authored-by: Marta Bondyra <[email protected]>","sha":"f7dad16597d9d29b312b877a4cb8c9e9bdf4f5ac"}},{"branch":"8.19","label":"v8.19.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"9.0","label":"v9.0.1","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> --------- Co-authored-by: kibanamachine <[email protected]>
1 parent 36a6916 commit 9fd0aea

File tree

4 files changed

+61
-24
lines changed

4 files changed

+61
-24
lines changed

src/platform/plugins/shared/controls/public/control_group/components/control_panel.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ export const ControlPanel = <ApiType extends DefaultControlApi = DefaultControlA
122122
const isEditable = viewMode === 'edit';
123123
const controlWidth = width ?? DEFAULT_CONTROL_WIDTH;
124124
const controlGrow = grow ?? DEFAULT_CONTROL_GROW;
125+
const controlLabel = usingTwoLineLayout ? panelTitle || defaultPanelTitle || '...' : undefined;
126+
125127
return (
126128
<EuiFlexItem
127129
ref={setNodeRef}
@@ -152,7 +154,9 @@ export const ControlPanel = <ApiType extends DefaultControlApi = DefaultControlA
152154
<EuiFormRow
153155
data-test-subj="control-frame-title"
154156
fullWidth
155-
label={usingTwoLineLayout ? panelTitle || defaultPanelTitle || '...' : undefined}
157+
label={controlLabel}
158+
id={`control-title-${uuid}`}
159+
aria-label={`Control for ${controlLabel}`}
156160
>
157161
<EuiFormControlLayout
158162
fullWidth

src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/components/range_slider_control.tsx

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,31 +23,33 @@ import { RangeSliderStrings } from '../range_slider_strings';
2323
import { rangeSliderControlStyles } from './range_slider.styles';
2424

2525
interface Props {
26-
fieldFormatter?: (value: string) => string;
26+
compressed: boolean;
27+
controlPanelClassName?: string;
2728
isInvalid: boolean;
2829
isLoading: boolean;
30+
fieldName: string;
2931
max: number | undefined;
3032
min: number | undefined;
31-
onChange: (value: RangeValue | undefined) => void;
3233
step: number;
33-
value: RangeValue | undefined;
3434
uuid: string;
35-
controlPanelClassName?: string;
36-
compressed: boolean;
35+
value: RangeValue | undefined;
36+
fieldFormatter?: (value: string) => string;
37+
onChange: (value: RangeValue | undefined) => void;
3738
}
3839

3940
export const RangeSliderControl: FC<Props> = ({
40-
fieldFormatter,
41+
compressed,
42+
controlPanelClassName,
4143
isInvalid,
4244
isLoading,
45+
fieldName,
4346
max,
4447
min,
45-
onChange,
4648
step,
47-
value,
4849
uuid,
49-
controlPanelClassName,
50-
compressed,
50+
value,
51+
fieldFormatter,
52+
onChange,
5153
}: Props) => {
5254
const rangeSliderRef = useRef<EuiDualRangeProps | null>(null);
5355

@@ -141,10 +143,14 @@ export const RangeSliderControl: FC<Props> = ({
141143
inputValue,
142144
testSubj,
143145
placeholder,
146+
ariaLabel,
147+
id,
144148
}: {
145149
inputValue: string;
146150
testSubj: string;
147151
placeholder: string;
152+
ariaLabel: string;
153+
id: string;
148154
}) => {
149155
return {
150156
isInvalid: undefined, // disabling this prop to handle our own validation styling
@@ -155,9 +161,12 @@ export const RangeSliderControl: FC<Props> = ({
155161
isInvalid ? styles.fieldNumbers.invalid : styles.fieldNumbers.valid,
156162
],
157163
className: 'rangeSliderAnchor__fieldNumber',
158-
'data-test-subj': `rangeSlider__${testSubj}`,
159164
value: inputValue === placeholder ? '' : inputValue,
160165
title: !isInvalid && step ? '' : undefined, // overwrites native number input validation error when the value falls between two steps
166+
'data-test-subj': `rangeSlider__${testSubj}`,
167+
'aria-label': ariaLabel,
168+
'aria-labelledby': `control-title-${id}`,
169+
id: `controls-range-slider-${id}`,
161170
};
162171
},
163172
[isInvalid, step, styles]
@@ -168,16 +177,20 @@ export const RangeSliderControl: FC<Props> = ({
168177
inputValue: displayedValue[0],
169178
testSubj: 'lowerBoundFieldNumber',
170179
placeholder: String(min ?? -Infinity),
180+
ariaLabel: RangeSliderStrings.control.getLowerBoundAriaLabel(fieldName),
181+
id: uuid,
171182
});
172-
}, [getCommonInputProps, min, displayedValue]);
183+
}, [getCommonInputProps, displayedValue, min, fieldName, uuid]);
173184

174185
const maxInputProps = useMemo(() => {
175186
return getCommonInputProps({
176187
inputValue: displayedValue[1],
177188
testSubj: 'upperBoundFieldNumber',
178189
placeholder: String(max ?? Infinity),
190+
ariaLabel: RangeSliderStrings.control.getUpperBoundAriaLabel(fieldName),
191+
id: uuid,
179192
});
180-
}, [getCommonInputProps, max, displayedValue]);
193+
}, [getCommonInputProps, displayedValue, max, fieldName, uuid]);
181194

182195
return (
183196
<span

src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.tsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -236,16 +236,25 @@ export const getRangesliderControlFactory = (): DataControlFactory<
236236
return {
237237
api,
238238
Component: ({ className: controlPanelClassName }) => {
239-
const [dataLoading, fieldFormatter, max, min, selectionHasNoResults, step, value] =
240-
useBatchedPublishingSubjects(
241-
dataLoading$,
242-
dataControlManager.api.fieldFormatter,
243-
max$,
244-
min$,
245-
selectionHasNoResults$,
246-
step$,
247-
selections.value$
248-
);
239+
const [
240+
dataLoading,
241+
fieldFormatter,
242+
max,
243+
min,
244+
selectionHasNoResults,
245+
step,
246+
value,
247+
fieldName,
248+
] = useBatchedPublishingSubjects(
249+
dataLoading$,
250+
dataControlManager.api.fieldFormatter,
251+
max$,
252+
min$,
253+
selectionHasNoResults$,
254+
step$,
255+
selections.value$,
256+
dataControlManager.api.fieldName$
257+
);
249258

250259
useEffect(() => {
251260
return () => {
@@ -260,6 +269,7 @@ export const getRangesliderControlFactory = (): DataControlFactory<
260269
return (
261270
<RangeSliderControl
262271
controlPanelClassName={controlPanelClassName}
272+
fieldName={fieldName}
263273
fieldFormatter={fieldFormatter}
264274
isInvalid={Boolean(value) && selectionHasNoResults}
265275
isLoading={typeof dataLoading === 'boolean' ? dataLoading : false}

src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/range_slider_strings.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ export const RangeSliderStrings = {
1919
i18n.translate('controls.rangeSlider.control.invalidSelectionWarningLabel', {
2020
defaultMessage: 'Selected range returns no results.',
2121
}),
22+
getLowerBoundAriaLabel: (fieldName: string) =>
23+
i18n.translate('controls.rangeSlider.control.lowerBoundAriaLabel', {
24+
defaultMessage: 'Range slider lower bound for {fieldName}',
25+
values: { fieldName },
26+
}),
27+
getUpperBoundAriaLabel: (fieldName: string) =>
28+
i18n.translate('controls.rangeSlider.control.lowerBoundAriaLabel', {
29+
defaultMessage: 'Range slider upper bound for {fieldName}',
30+
values: { fieldName },
31+
}),
2232
},
2333
editor: {
2434
getStepTitle: () =>

0 commit comments

Comments
 (0)