Direct answer
Enforce focus trapping in Cockpit custom modals with role="dialog", aria-modal="true", and aria-labelledby referencing the modal title. Keyboard focus must cycle only among tabbable elements inside the modal, and Escape must close the modal and return focus to the triggering element. For dynamic log and metric views, use a single persistent live region with aria-live="polite" and aria-atomic="false", append new lines as text nodes rather than replacing innerHTML, and keep the region visually hidden with clipping rather than display:none.
Confirmed behavior and assumptions
Cockpit is built with PatternFly React components. PatternFly's Modal component provides focus trapping internally; custom or plugin-built modals may bypass it and require a manual focus-zone wrapper. This answer assumes Cockpit on CentOS Stream 9 or 10 with PatternFly 4 or 5 installed. PatternFly 5 relies on react-aria-modal; earlier versions may behave differently and should be treated as unverified.
Steps for this case
- Audit each Cockpit plugin modal (for example, Podman, storage, or kdump) to determine whether it uses PatternFly
Modal or a custom overlay.
- Add
role="dialog", aria-modal="true", and aria-labelledby to every custom modal container.
- Implement a focus-zone wrapper for custom modals that re-evaluates tabbable elements after asynchronous content loads and restores the previous
document.activeElement on close.
- Add one persistent
aria-live="polite" aria-atomic="false" region per log view and append new log entries as text nodes.
- Set visual gauges to
aria-live="off" and use a separate polite region for threshold-crossing announcements only.
- Preserve or re-initialize live regions across Cockpit's PJAX/fetch route changes.
Verification
Test with keyboard-only navigation: open a confirmation modal, press Tab and Shift+Tab, then Escape. Focus should remain inside the modal and return to the trigger button. Open Developer Tools and confirm the log live region is present and updates without re-reading the entire buffer. If you have repository access, run npm test with @patternfly/a11y-testing to catch focus-trap and live-region regressions.
Missing diagnostic detail: what is the installed @patternfly/react-core version, and are the affected modals custom plugin components or PatternFly Modal instances? This determines whether you need a custom focus-zone implementation or only attribute corrections.