Skip to content

Site setup content types add new - CMS UI - a11y#8058

Open
Wagner3UB wants to merge 11 commits intomainfrom
site-setup-content-types-add-new-a11y
Open

Site setup content types add new - CMS UI - a11y#8058
Wagner3UB wants to merge 11 commits intomainfrom
site-setup-content-types-add-new-a11y

Conversation

@Wagner3UB
Copy link
Copy Markdown
Contributor

@Wagner3UB Wagner3UB commented Mar 27, 2026

Accessibility improvements for ModalForm and Content Types panel

Fixed several accessibility issues in the ModalForm component and the Content Types control panel:

  • Added proper focus management: focus returns to the trigger button when a modal dialog is closed or submitted
  • Added aria-live region announcements when a modal opens or closes (screen reader support)
  • Added aria-modal support to the modal dialog
  • Updated button ID from #toolbar-add to #toolbar-add-content-type for better semantic clarity
  • Updated Cypress tests to reflect the new button ID and CSS classes
  • Added translations for the new i18n strings across all supported locales

Issue: #5141

@Wagner3UB Wagner3UB self-assigned this Mar 27, 2026
Copy link
Copy Markdown
Collaborator

@stevepiercy stevepiercy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Just the news. Also merge #8077 to fix linkcheck.

@@ -0,0 +1 @@
Fixed accessibility issues in ModalForm: focus management, aria-live announcements and aria-modal support @Wagner3UB
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Fixed accessibility issues in ModalForm: focus management, aria-live announcements and aria-modal support @Wagner3UB
Fixed accessibility issues in `ModalForm` with focus management, `aria-live` announcements, and `aria-modal` support. @Wagner3UB

@github-project-automation github-project-automation bot moved this from In progress to Review in progress in RedTurtle priorities Apr 2, 2026
@github-project-automation github-project-automation bot moved this from In progress to Review in progress in Accessibility Apr 2, 2026
@wesleybl
Copy link
Copy Markdown
Member

wesleybl commented Apr 7, 2026

@Wagner3UB Perhaps it would be better to convert ModalForm to a functional component before applying these changes? See:

#7685

@wesleybl
Copy link
Copy Markdown
Member

wesleybl commented Apr 7, 2026

The bad thing about waiting for the conversion to a functional component is that the backport to Volto 18 will become more difficult.

@sneridagh said that we cannot do the backport of the conversion to functional components.

But the changes here can work for Volto 18.

@davisagli
Copy link
Copy Markdown
Member

@wesleybl From my perspective, the conversion to a functional component is a separate matter. We merge the one that is ready first, and then update the other one.

@Wagner3UB
Copy link
Copy Markdown
Contributor Author

Perhaps it would be better to convert ModalForm to a functional component before applying these changes? See:

@plone/volto-team What do you think, folks? I can sustain these changes for Volto 18 and do the refactor that @wesleybl suggested. More work to do, but, can be beneficial.

@wesleybl
Copy link
Copy Markdown
Member

wesleybl commented Apr 9, 2026

@Wagner3UB I think to make backporting to Volto 18 easier, you can continue here and then we'll do the conversion to functional.

* @extends Component
*/
class ModalForm extends Component {
headerId = `modal-title-${Math.random().toString(36).slice(2)}`;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's best to use a static counter to avoid collisions. And it should also be inside the constructor:

static idCounter = 0;
constructor(props) {
  this.headerId = `modal-title-${++ModalForm.idCounter}`;
}

@@ -215,6 +226,22 @@ class ModalForm extends Component {
* @param {Object} prevState
*/
async componentDidUpdate(prevProps, prevState) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no await. You can remove the async.

aria-labelledby={this.headerId}
aria-modal="true"
>
<Header id={this.headerId} aria-live="assertive" aria-atomic="true">
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's already an aria-live="assertive" in the div above. It's best to remove it from here:

Suggested change
<Header id={this.headerId} aria-live="assertive" aria-atomic="true">
<Header id={this.headerId}>

Comment on lines +400 to +412
{/* Sentinel: closing the modal when the user tabs past the last element */}
{onCancel && (
<button
type="button"
onFocus={() => {
if (this.announceRef.current) {
this.announceRef.current.textContent =
this.props.intl.formatMessage(messages.dialogClosed);
}
onCancel();
}}
style={{ position: 'absolute', opacity: 0 }}
/>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it strange to close the modal with a tab. I think there should be an explicit action to close it. But the way it exits the modal is also strange. I think it should stay in a loop inside the modal.

opacity: 0,
}}
/>
<Modal
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add:

role="dialog"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Review in progress
Status: Review in progress

Development

Successfully merging this pull request may close these issues.

4 participants