Skip to content

Commit ac3c8dd

Browse files
alexwizpCopilot
andauthored
[9.2] a11y: Fix @elastic/eui/require-aria-label-for-modals violations across 43 presentation/maps/canvas files (#259314) (#260758)
# Backport This will backport the following commits from `main` to `9.2`: - [a11y: Fix `@elastic/eui/require-aria-label-for-modals` violations across 43 presentation/maps/canvas files (#259314)](#259314) <!--- Backport version: 10.2.0 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Copilot","email":"198982749+Copilot@users.noreply.github.com"},"sourceCommit":{"committedDate":"2026-03-31T19:09:22Z","message":"a11y: Fix `@elastic/eui/require-aria-label-for-modals` violations across 43 presentation/maps/canvas files (#259314)\n\nCloses: https://github.com/elastic/kibana/issues/259305\n\n43 EUI overlay components (`EuiModal`, `EuiFlyout`, `EuiPopover`,\n`EuiWrappingPopover`) were missing required `aria-label` or\n`aria-labelledby` props, failing WCAG 2.2 AA screen-reader accessibility\nrequirements.\n\n## Approach\n\n**EuiModal / EuiFlyout** — preferred `aria-labelledby` pattern using\n`useGeneratedHtmlId`:\n```tsx\nconst modalTitleId = useGeneratedHtmlId();\n// ...\n<EuiModal aria-labelledby={modalTitleId} ...>\n <EuiModalHeader>\n <EuiModalHeaderTitle id={modalTitleId}>...</EuiModalHeaderTitle>\n```\n\n**EuiPopover / EuiWrappingPopover** — `aria-label` with i18n string:\n```tsx\n<EuiPopover\n aria-label={i18n.translate('xpack.maps.tileErrorsList.popoverAriaLabel', {\n defaultMessage: 'Tile errors',\n })}\n ...\n>\n```\n\n## Scope\n\n- **6 modal/flyout components**: `delete_grid_section_modal`,\n`labs_flyout`, `asset_manager`, `keyboard_shortcuts_doc`,\n`saved_elements_modal`, `custom_icon_modal` (class component — used\n`aria-label` with title prop)\n- **37 popover components**: reused existing label variables\n(`displayName`, `strings.getMoreActionsLabel()`, etc.) where available;\nadded new `i18n.translate()` calls otherwise\n- Added `i18n` and `useGeneratedHtmlId` imports only where needed\n\n\n---\n\n📱 Kick off Copilot coding agent tasks wherever you are with [GitHub\nMobile](https://gh.io/cca-mobile-docs), available on iOS and Android.\n\n---------\n\nCo-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>\nCo-authored-by: Alexey Antonov <alexwizp@gmail.com>\nCo-authored-by: alexwizp <20072247+alexwizp@users.noreply.github.com>","sha":"93c442574a5ea72f599daa9ebca41a4b71601544","branchLabelMapping":{"^v9.4.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","💝community","backport:version","v9.4.0","v9.3.3","v9.2.8","a11y:agent-pr"],"title":"a11y: Fix `@elastic/eui/require-aria-label-for-modals` violations across 43 presentation/maps/canvas files","number":259314,"url":"https://github.com/elastic/kibana/pull/259314","mergeCommit":{"message":"a11y: Fix `@elastic/eui/require-aria-label-for-modals` violations across 43 presentation/maps/canvas files (#259314)\n\nCloses: https://github.com/elastic/kibana/issues/259305\n\n43 EUI overlay components (`EuiModal`, `EuiFlyout`, `EuiPopover`,\n`EuiWrappingPopover`) were missing required `aria-label` or\n`aria-labelledby` props, failing WCAG 2.2 AA screen-reader accessibility\nrequirements.\n\n## Approach\n\n**EuiModal / EuiFlyout** — preferred `aria-labelledby` pattern using\n`useGeneratedHtmlId`:\n```tsx\nconst modalTitleId = useGeneratedHtmlId();\n// ...\n<EuiModal aria-labelledby={modalTitleId} ...>\n <EuiModalHeader>\n <EuiModalHeaderTitle id={modalTitleId}>...</EuiModalHeaderTitle>\n```\n\n**EuiPopover / EuiWrappingPopover** — `aria-label` with i18n string:\n```tsx\n<EuiPopover\n aria-label={i18n.translate('xpack.maps.tileErrorsList.popoverAriaLabel', {\n defaultMessage: 'Tile errors',\n })}\n ...\n>\n```\n\n## Scope\n\n- **6 modal/flyout components**: `delete_grid_section_modal`,\n`labs_flyout`, `asset_manager`, `keyboard_shortcuts_doc`,\n`saved_elements_modal`, `custom_icon_modal` (class component — used\n`aria-label` with title prop)\n- **37 popover components**: reused existing label variables\n(`displayName`, `strings.getMoreActionsLabel()`, etc.) where available;\nadded new `i18n.translate()` calls otherwise\n- Added `i18n` and `useGeneratedHtmlId` imports only where needed\n\n\n---\n\n📱 Kick off Copilot coding agent tasks wherever you are with [GitHub\nMobile](https://gh.io/cca-mobile-docs), available on iOS and Android.\n\n---------\n\nCo-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>\nCo-authored-by: Alexey Antonov <alexwizp@gmail.com>\nCo-authored-by: alexwizp <20072247+alexwizp@users.noreply.github.com>","sha":"93c442574a5ea72f599daa9ebca41a4b71601544"}},"sourceBranch":"main","suggestedTargetBranches":["9.3","9.2"],"targetPullRequestStates":[{"branch":"main","label":"v9.4.0","branchLabelMappingKey":"^v9.4.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/259314","number":259314,"mergeCommit":{"message":"a11y: Fix `@elastic/eui/require-aria-label-for-modals` violations across 43 presentation/maps/canvas files (#259314)\n\nCloses: https://github.com/elastic/kibana/issues/259305\n\n43 EUI overlay components (`EuiModal`, `EuiFlyout`, `EuiPopover`,\n`EuiWrappingPopover`) were missing required `aria-label` or\n`aria-labelledby` props, failing WCAG 2.2 AA screen-reader accessibility\nrequirements.\n\n## Approach\n\n**EuiModal / EuiFlyout** — preferred `aria-labelledby` pattern using\n`useGeneratedHtmlId`:\n```tsx\nconst modalTitleId = useGeneratedHtmlId();\n// ...\n<EuiModal aria-labelledby={modalTitleId} ...>\n <EuiModalHeader>\n <EuiModalHeaderTitle id={modalTitleId}>...</EuiModalHeaderTitle>\n```\n\n**EuiPopover / EuiWrappingPopover** — `aria-label` with i18n string:\n```tsx\n<EuiPopover\n aria-label={i18n.translate('xpack.maps.tileErrorsList.popoverAriaLabel', {\n defaultMessage: 'Tile errors',\n })}\n ...\n>\n```\n\n## Scope\n\n- **6 modal/flyout components**: `delete_grid_section_modal`,\n`labs_flyout`, `asset_manager`, `keyboard_shortcuts_doc`,\n`saved_elements_modal`, `custom_icon_modal` (class component — used\n`aria-label` with title prop)\n- **37 popover components**: reused existing label variables\n(`displayName`, `strings.getMoreActionsLabel()`, etc.) where available;\nadded new `i18n.translate()` calls otherwise\n- Added `i18n` and `useGeneratedHtmlId` imports only where needed\n\n\n---\n\n📱 Kick off Copilot coding agent tasks wherever you are with [GitHub\nMobile](https://gh.io/cca-mobile-docs), available on iOS and Android.\n\n---------\n\nCo-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>\nCo-authored-by: Alexey Antonov <alexwizp@gmail.com>\nCo-authored-by: alexwizp <20072247+alexwizp@users.noreply.github.com>","sha":"93c442574a5ea72f599daa9ebca41a4b71601544"}},{"branch":"9.3","label":"v9.3.3","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"9.2","label":"v9.2.8","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
1 parent 39d984a commit ac3c8dd

File tree

41 files changed

+133
-5
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+133
-5
lines changed

examples/embeddable_examples/public/app/presentation_container_example/components/add_button.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import type { ReactElement } from 'react';
1111
import React, { useEffect, useState } from 'react';
1212
import { EuiButton, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui';
13+
import { i18n } from '@kbn/i18n';
1314
import type { UiActionsStart } from '@kbn/ui-actions-plugin/public';
1415
import { ADD_PANEL_TRIGGER } from '@kbn/ui-actions-plugin/public';
1516
import type { PublishingSubject, ViewMode } from '@kbn/presentation-publishing';
@@ -79,6 +80,9 @@ export function AddButton({ pageApi, uiActions }: { pageApi: unknown; uiActions:
7980
}}
8081
panelPaddingSize="none"
8182
anchorPosition="downLeft"
83+
aria-label={i18n.translate('embeddableExamples.addPanelPopover.ariaLabel', {
84+
defaultMessage: 'Add panel',
85+
})}
8286
>
8387
<EuiContextMenuPanel items={items} />
8488
</EuiPopover>

examples/grid_example/public/grid_layout_options.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ export const GridLayoutOptions = ({
4343
}
4444
isOpen={isSettingsPopoverOpen}
4545
closePopover={() => setIsSettingsPopoverOpen(false)}
46+
aria-label={i18n.translate('examples.gridExample.settingsPopover.ariaLabel', {
47+
defaultMessage: 'Layout settings',
48+
})}
4649
>
4750
<>
4851
<EuiFormRow

src/platform/packages/private/kbn-grid-layout/grid/grid_section/delete_grid_section_modal.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
EuiModalFooter,
1818
EuiModalHeader,
1919
EuiModalHeaderTitle,
20+
useGeneratedHtmlId,
2021
} from '@elastic/eui';
2122
import { i18n } from '@kbn/i18n';
2223

@@ -32,16 +33,18 @@ export const DeleteGridSectionModal = ({
3233
setDeleteModalVisible: (visible: boolean) => void;
3334
}) => {
3435
const { gridLayoutStateManager } = useGridLayoutContext();
36+
const modalTitleId = useGeneratedHtmlId();
3537

3638
return (
3739
<EuiModal
3840
data-test-subj={`kbnGridLayoutDeleteSectionModal-${sectionId}`}
41+
aria-labelledby={modalTitleId}
3942
onClose={() => {
4043
setDeleteModalVisible(false);
4144
}}
4245
>
4346
<EuiModalHeader>
44-
<EuiModalHeaderTitle>
47+
<EuiModalHeaderTitle id={modalTitleId}>
4548
{i18n.translate('kbnGridLayout.deleteGridSectionModal.title', {
4649
defaultMessage: 'Delete section',
4750
})}

src/platform/plugins/private/presentation_panel/public/panel_component/panel_header/presentation_panel_hover_actions.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ export const PresentationPanelHoverActions = ({
477477
isOpen={isContextMenuOpen}
478478
className={contextMenuClasses}
479479
closePopover={onClose}
480+
aria-label={getContextMenuAriaLabel(title, index)}
480481
data-test-subj={
481482
isContextMenuOpen
482483
? 'embeddablePanelContextMenuOpen'

src/platform/plugins/shared/dashboard/public/dashboard_actions/filters_notification_popover.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ export function FiltersNotificationPopover({ api }: { api: FiltersNotificationAc
110110
}
111111
}}
112112
anchorPosition="upCenter"
113+
aria-label={displayName}
113114
>
114115
<EuiForm
115116
component="div"

src/platform/plugins/shared/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ export function InternalDashboardTopNav({
296296
isOpen={isPopoverOpen}
297297
closePopover={() => setIsPopoverOpen(false)}
298298
panelStyle={{ maxWidth: 250 }}
299+
aria-label={dashboardManagedBadge.getBadgeAriaLabel()}
299300
>
300301
<FormattedMessage
301302
id="dashboard.managedContentPopoverButton"

src/platform/plugins/shared/inspector/public/ui/inspector_view_chooser.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
import { FormattedMessage } from '@kbn/i18n-react';
11+
import { i18n } from '@kbn/i18n';
1112
import React, { Component } from 'react';
1213
import PropTypes from 'prop-types';
1314
import {
@@ -117,6 +118,9 @@ export class InspectorViewChooser extends Component<Props, State> {
117118
panelPaddingSize="none"
118119
anchorPosition="downRight"
119120
repositionOnScroll
121+
aria-label={i18n.translate('inspector.viewChooser.popover.ariaLabel', {
122+
defaultMessage: 'Inspector view selector',
123+
})}
120124
>
121125
<EuiContextMenuPanel items={views.map(this.renderView)} />
122126
</EuiPopover>

src/platform/plugins/shared/presentation_util/public/components/labs/labs_flyout.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
EuiSpacer,
2121
EuiText,
2222
EuiTitle,
23+
useGeneratedHtmlId,
2324
} from '@elastic/eui';
2425
import type { ReactNode } from 'react';
2526
import React, { useEffect, useMemo, useRef, useState } from 'react';
@@ -64,6 +65,7 @@ export const getOverridenCount = (projects: Record<ProjectID, Project>) =>
6465
export const LabsFlyout = (props: Props) => {
6566
const { solutions, onEnabledCountChange = () => {}, onClose } = props;
6667
const labsService = useMemo(() => getPresentationLabsService(), []);
68+
const flyoutTitleId = useGeneratedHtmlId();
6769

6870
const [projects, setProjects] = useState(labsService.getProjects());
6971
const [overrideCount, setOverrideCount] = useState(getOverridenCount(projects));
@@ -134,10 +136,11 @@ export const LabsFlyout = (props: Props) => {
134136
onClose={onClose}
135137
hideCloseButton={true}
136138
maskProps={{ headerZindexLocation: 'below' }}
139+
aria-labelledby={flyoutTitleId}
137140
>
138141
<EuiFlyoutHeader hasBorder>
139142
<EuiTitle size="m">
140-
<h2>
143+
<h2 id={flyoutTitleId}>
141144
<EuiFlexGroup gutterSize="s" alignItems="center" responsive={false}>
142145
<EuiFlexItem grow={false}>
143146
<EuiIcon type="beaker" size="l" />

src/platform/plugins/shared/unified_search/public/filters_builder/filter_item/actions/minimised_actions.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,13 @@ export const MinimisedFilterItemActions: FC<FilterItemActionsProps> = (props) =>
3333
);
3434

3535
return (
36-
<EuiPopover ownFocus={false} button={button} isOpen={isPopoverOpen} closePopover={closePopover}>
36+
<EuiPopover
37+
ownFocus={false}
38+
button={button}
39+
isOpen={isPopoverOpen}
40+
closePopover={closePopover}
41+
aria-label={strings.getMoreActionsLabel()}
42+
>
3743
<FilterItemActions {...props} minimizePaddings={true} />
3844
</EuiPopover>
3945
);

src/platform/plugins/shared/unified_search/public/query_string_input/add_filter_popover.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ const AddFilterPopoverComponent = React.memo(function AddFilterPopover({
9292
initialFocus=".filterEditor__hiddenItem"
9393
ownFocus
9494
repositionOnScroll
95+
aria-label={strings.getAddFilterButtonLabel()}
9596
>
9697
<FilterEditorWrapper
9798
indexPatterns={indexPatterns}

0 commit comments

Comments
 (0)