diff --git a/x-pack/solutions/security/plugins/security_solution/public/exceptions/pages/shared_lists/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/exceptions/pages/shared_lists/index.tsx
index 290d9e02e7eed..b6ae7cb10dd75 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/exceptions/pages/shared_lists/index.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/exceptions/pages/shared_lists/index.tsx
@@ -19,6 +19,7 @@ import {
EuiPageHeader,
EuiPagination,
EuiPopover,
+ EuiScreenReaderLive,
EuiSpacer,
EuiText,
} from '@elastic/eui';
@@ -148,6 +149,7 @@ export const SharedLists = React.memo(() => {
const [exportDownload, setExportDownload] = useState<{ name?: string; blob?: Blob }>({});
const [displayImportListFlyout, setDisplayImportListFlyout] = useState(false);
+ const [screenReaderMessage, setScreenReaderMessage] = useState('');
const { addError, addSuccess } = useAppToasts();
// Loading states
@@ -202,7 +204,18 @@ export const SharedLists = React.memo(() => {
const handleExportSuccess = useCallback(
(listId: string, name: string) =>
(blob: Blob): void => {
- addSuccess(i18n.EXCEPTION_LIST_EXPORTED_SUCCESSFULLY(name));
+ const message = i18n.EXCEPTION_LIST_EXPORTED_SUCCESSFULLY(name);
+ addSuccess(message);
+ // If the same list is exported twice in a row, React won't re-render
+ // since state hasn't changed, so the live region won't re-announce.
+ // Clearing to '' first ensures VoiceOver sees a new change on the next frame.
+ setScreenReaderMessage((current) => {
+ if (current === message) {
+ requestAnimationFrame(() => setScreenReaderMessage(message));
+ return '';
+ }
+ return message;
+ });
setExportDownload({ name: listId, blob });
},
[addSuccess]
@@ -468,6 +481,9 @@ export const SharedLists = React.memo(() => {
return (
<>
+
+ {screenReaderMessage}
+