close
Skip to content

Admin UI: Fix type mismatch between Page title and NavigableRegion ariaLabel#75899

Merged
simison merged 7 commits intoWordPress:trunkfrom
jeherve:fix/page-arialabel-type-mismatch
Mar 3, 2026
Merged

Admin UI: Fix type mismatch between Page title and NavigableRegion ariaLabel#75899
simison merged 7 commits intoWordPress:trunkfrom
jeherve:fix/page-arialabel-type-mismatch

Conversation

@jeherve
Copy link
Contributor

@jeherve jeherve commented Feb 25, 2026

What?

Closes #75898

Add an explicit ariaLabel prop to the Page component and make NavigableRegion's ariaLabel optional, fixing a type mismatch between the two components.

Why?

Page accepts title as React.ReactNode but passes it directly to NavigableRegion as ariaLabel, which expects a string and renders it as an aria-label DOM attribute. If a caller passes JSX as title (e.g., a title with an icon), the aria-label renders as [object Object], breaking accessibility for screen readers.

How?

  • Add an optional ariaLabel?: string prop to Page.
  • When resolving the value for NavigableRegion's ariaLabel:
    • Use the explicit ariaLabel prop if provided.
    • Fall back to title if it's a plain string.
    • Otherwise pass undefined, which omits the aria-label attribute from the DOM.
  • Make NavigableRegion's ariaLabel prop optional (string | undefined). React naturally omits the attribute when the value is undefined.

All existing callers pass string titles and don't use the new ariaLabel prop, so behavior is unchanged.

Testing Instructions

  1. Verify existing behavior is preserved: open any admin page that uses the Page component (e.g., Templates, Patterns, Styles). Inspect the wrapping region element — it should still have a valid aria-label matching the page title.
  2. Verify the fix: use the Page component with a JSX title and an explicit ariaLabel:
    <Page title={<><Icon /><span>My Page</span></>} ariaLabel="My Page">
    Inspect the DOM — the region element's aria-label should be "My Page", not [object Object].
  3. Verify graceful fallback: use Page with a JSX title and no ariaLabel. The region element should have no aria-label attribute rather than a broken one.

Testing Instructions for Keyboard

No UI changes — this PR fixes a prop type and adds an optional prop. Keyboard interaction is unaffected. Accessibility is improved: screen readers will no longer encounter [object Object] as a region label.

Screenshots or screencast

N/A — this is a type/API fix with no visual changes.

…iaLabel

Page accepts title as React.ReactNode but passes it directly to
NavigableRegion's ariaLabel, which expects a string and renders it as
an aria-label DOM attribute. Passing JSX as title would result in
[object Object] in the DOM, breaking accessibility.

Add an explicit ariaLabel prop to Page for callers that use rich
content in title. When ariaLabel is not provided, fall back to title
only if it's a string. Make NavigableRegion's ariaLabel optional so
it gracefully handles undefined values.
@github-actions
Copy link

github-actions bot commented Feb 25, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: jeherve <jeherve@git.wordpress.org>
Co-authored-by: youknowriad <youknowriad@git.wordpress.org>
Co-authored-by: simison <simison@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@simison simison added the [Type] Bug An existing feature does not function as intended label Feb 25, 2026
@simison
Copy link
Member

simison commented Feb 25, 2026

Can you also update the changelog?

@simison simison requested a review from jameskoster February 25, 2026 11:31
@simison simison added the [Package] Admin UI /packages/admin-ui label Feb 25, 2026
@jeherve jeherve force-pushed the fix/page-arialabel-type-mismatch branch from e3e354b to dde0800 Compare February 25, 2026 12:40
@youknowriad
Copy link
Contributor

Is making the ariaLabel optional in NavigableRegion the right move? Isn't the main idea of that component is to be an accessible aria region and without a label, it's a bug basically?

@jeherve
Copy link
Contributor Author

jeherve commented Feb 25, 2026

Is making the ariaLabel optional in NavigableRegion the right move? Isn't the main idea of that component is to be an accessible aria region and without a label, it's a bug basically?

That's a good point. I suppose there should always be a label. I'm not sure what's the best way to go about it ; I didn't want to make it mandatory because I wasn't sure it was a good idea, since there are already components that rely on NavigableRegion out there. What would you recommend?

@youknowriad
Copy link
Contributor

Are there components that rely on this component that don't provide the label? I feel like if it's the case, these components should be updated to provide one no?

@jeherve
Copy link
Contributor Author

jeherve commented Feb 26, 2026

I would agree, and we can do that in the Gutenberg codebase (I've just done so), and we can then make the new prop mandatory, but how can we account for third-parties using the package and not knowing about those changes? Is it okay to introduce a new mandatory prop like this?

@github-actions github-actions bot added [Package] Edit Post /packages/edit-post [Package] Interface /packages/interface labels Feb 26, 2026
Add explicit ariaLabel to all Page consumers, removing the
implicit title-based fallback. This ensures every navigable
region has a deliberate accessibility label.
@github-actions github-actions bot added the [Package] Edit Site /packages/edit-site label Feb 26, 2026
@youknowriad
Copy link
Contributor

Is it okay to introduce a new mandatory prop like this?

I actually thought the prop existed in the component before and was mistyped, but it seems the prop didn't exist but instead "aria-label" prop was being used.

what do you think is best? keep using aria-label or introduce a new ariaLabel. Both options seem possible as long as we keep the previous aria-label passing working (which seems to be the case now)


return (
<NavigableRegion className={ classes } ariaLabel={ title }>
<NavigableRegion className={ classes } ariaLabel={ ariaLabel }>
Copy link
Contributor

Choose a reason for hiding this comment

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

Where I have trouble with this PR is that I don't think we should force "Page" users to provide two titles (a title and an ariaLabel). Why can't we use the title as ariaLabel? or maybe the ariaLabel should be optional when we want these two things to be different.

Copy link
Member

Choose a reason for hiding this comment

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

+1, as long as title is a string, it should be enough:

<Page title={ <PageNameWithLogo /> } ariaLabel="Page name" />
and
<Page title="Page name" />

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why can't we use the title as ariaLabel? or maybe the ariaLabel should be optional when we want these two things to be different.

I pushed a commit to do just that, let me know what you think.

Copy link
Member

Choose a reason for hiding this comment

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

Looks good!

<Page title={ __( 'Route not found' ) } hasPadding>
<Page
title={ __( 'Route not found' ) }
ariaLabel={ __( 'Route not found' ) }
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment is very visible here, why as a consumer I have to prove my title twice.

When title is a string, use it as the aria-label automatically.
This avoids forcing callers to duplicate the same value in both
title and ariaLabel. An explicit ariaLabel is only needed when
title is JSX or a different label is desired.
@github-actions github-actions bot removed the [Package] Edit Site /packages/edit-site label Feb 26, 2026
@simison simison merged commit 9ee534a into WordPress:trunk Mar 3, 2026
41 of 44 checks passed
@github-actions github-actions bot added this to the Gutenberg 22.7 milestone Mar 3, 2026
alecgeatches pushed a commit to Automattic/gutenberg that referenced this pull request Mar 3, 2026
…iaLabel (WordPress#75899)

Page accepts title as React.ReactNode but passes it directly to
NavigableRegion's ariaLabel, which expects a string and renders it as
an aria-label DOM attribute. Passing JSX as title would result in
[object Object] in the DOM, breaking accessibility.

Add an explicit ariaLabel prop to Page for callers that use rich
content in title. When ariaLabel is not provided, fall back to title
only if it's a string. Make NavigableRegion's ariaLabel optional so
it gracefully handles undefined values.


Co-authored-by: jeherve <jeherve@git.wordpress.org>
Co-authored-by: youknowriad <youknowriad@git.wordpress.org>
Co-authored-by: simison <simison@git.wordpress.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package] Admin UI /packages/admin-ui [Package] Edit Post /packages/edit-post [Package] Interface /packages/interface [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Admin UI: Type mismatch between Page title prop and NavigableRegion ariaLabel

3 participants