Skip to content

UI: Remove speak functionality from Notice primitive #82701

Closed

Description

@aduth

What problem does this address?

Related: #80706

Currently, the Notice component implementation in @wordpress/ui includes built-in functionality to use @wordpress/a11y's speak utility to announce the content of the notice.

This is problematic in a few ways:

  • The @wordpress/ui package is a set of low-level UI primitives that are intended to be used in a variety of use-cases, and there may be cases where a UI should contain a notice that is not a dynamic message that needs to be announced to screen readers (e.g. notices which are statically present at page load). Dynamic notices are a common use-case and should continue to be handled with sensible defaults, but this should happen at a higher level of abstraction.
  • The current default implementation of the spoken message is naive and often produces an undesirable result. As explored in UI: Update Notice spoken message default to plaintext title and description #80706, the current behavior announces the entire HTML contents of the notice banner, including any actions that it contains. So the spoken message for the default Notice Storybook story would be "Notice Title Description text with details about this notification. Primary button Secondary button Link". The lack of any punctuation to abbreviate the spoken content and the inclusion of all details (e.g. actions) may make the announcement difficult to understand.

Related guidance:

The most important thing to know about the alert role is that it's for content that is dynamically displayed, not for content that appears on page load. [...] For example, if a page loads with multiple visible alerts scattered throughout, the alert role should not be used, as the messages were not dynamically triggered.

https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/alert_role

What is your proposed solution?

Move the built-in speak functionality from the Notice component to a level of abstraction appropriate for the expected interaction of dynamic notice content, e.g. the editor notices region as mentioned in #80706 (comment) .

Needs decision: This cannot be implemented until settling on a proposed direction for where the live announcements should happen.

Activity

  1. added
    [Type] TaskIssues or PRs that have been broken down into an individual action to take
    Needs DecisionNeeds a decision to be actionable or relevant
    on Sep 9, 2026
  2. joedolson commented on Sep 9, 2026

    @joedolson
    Contributor

    This will probably also need an audit of every usage of the Notice component to ensure that notices are spoken appropriately when needed.

    But I agree that this naive implementation is flawed: the messages should be explicitly defined, so that they contain all the relevant content and punctuation to be understandable. There are also specific cases where a notice should not be announced - if focus is moved to the notice, then it should not also be announced. I'm not sure whether there are examples of that use case, but it would probably be better to allow for it.

    See #9442, #15708, etc.

  3. aduth commented on Sep 9, 2026

    @aduth
    MemberAuthor

    It's worth noting that while the issue is directed at the @wordpress/ui component, the specific implementation details were presumably inherited from the @wordpress/components implementation that has the same behavior. I raise this to clarify a few points:

    • This problem is not unique to the @wordpress/ui implementation
    • @wordpress/components inherently lives at a higher level of abstraction and this may be more appropriate there than it is in @wordpress/ui (see Design System: Support for admin redesign #71196 and design system introduction documentation for more of the context around this)
    • Most of the current notices usage today uses the @wordpress/components implementation, but as there's a desire to start adopting the new implementation (example), we should plan to account for this in whatever new usage is introduced
  4. simison commented on Sep 10, 2026

    @simison
    Member

    the messages should be explicitly defined, so that they contain all the relevant content and punctuation to be understandable.

    What if we removed the behaviour that automatically announces and uses the description, but left the API in place? It would then become a documented convenience feature which folks can opt into by just providing spokenMessage. politeness could then continue to get set automatically depending on Notice intent.

    Not sure if there's value in having the API instead of just allowing consumers to define role="alert" etc though.

  5. ciampo commented on Sep 10, 2026

    @ciampo
    Contributor

    To me, there's a wider conversation to have about whether "plain" (ie not tied to Gutenberg/WordPress app) UI components should announce updates to assistive technology.

    I believe the answer should be "yes" (TBD if opt-in or opt-out).

    Separately, but as important, we should make sure that components performing the announcement do it in the same way, and with a consistent APIs. We currently have:

    • speak() internal utility vs internal base-ui implementation
    • default, non-configurable behaviour vs base-ui's subcomponent-based approach (example)
  6. aduth commented on Sep 10, 2026

    @aduth
    MemberAuthor

    For another related parallel to BaseUI, it appears that the implementation of Toast.Viewport is somewhat similar to ideas I've tossed around in the original issue and in #80706: It's the container element that handles announcements of new content, where each new spoken message is derived from the plaintext title and description. The idea of deriving plaintext content from the individual feedback component is similar to what I was exploring in #80706. And a container component is similar to what we have with @wordpress/notices components. Taking this approach could help avoid some of the issues of working with an explicit spokenMessage.

    With an explicit spokenMessage, there's a challenge in whether it's required or not, particularly in context of this issue in highlighting that not all notices should have spoken announcements:

    1. If it's required, it creates some developer experience friction, increases the potential for deviation between spoken and visible messages, and biases a default assumption that notices should have spoken announcements. We'd likely need an escape hatch like spokenMessage={ false } to support notices without accompanying spoken message.
    2. If it's not required, then it's too easily overlooked, and developers may omit a spoken message when one would be appropriate.
  7. aduth commented on Sep 14, 2026

    @aduth
    MemberAuthor

    Here's a proposal:

    • Default speaking behavior is removed from Notice
    • A new Notice.List component provides both visual layout and to a live region container for notice announcement content.
      • It lives in @wordpress/ui
      • Unlike NoticeList in @wordpress/components, it is compositional: children are Notice.Root, not a notices prop
      • @wordpress/notices implementation can switch from NoticeList to Notice.List internally and handle data store interactions
      • Always renders as a live region: Static content won't be announced because the behavior of live regions is that they won't announce any notice content that exists initially. But dynamically added notices will be announced.
      • Notice.List renders its own live region container whose content is populated by context-registered title and description of descendent notices, something of a hybrid between BaseUI's Toast.Viewport and UI: Update Notice spoken message default to plaintext title and description #80706
      • The actual live region might be children of the container element itself, alongside the rendered notices. There would be a live region per politeness, and we infer politeness level from intent (maybe configurable).
      • The live regions aren't rendered if the list has focus, to address @joedolson 's point in UI: Remove speak functionality from Notice primitive #82701 (comment), and following BaseUI's similar implementation
    • With consideration for snackbar, we may eventually want some sort of shared abstraction here for generalizing the "live region announcing contents of context-registered content" via something like a useAnnouncement hook or LiveRegion internal abstraction. We may not need this for an initial implementation.
  8. ciampo commented on Sep 14, 2026

    @ciampo
    Contributor

    Keeping announcement behavior in @wordpress/ui through composition makes sense to me. Notice.List seems like a reasonable place for it.

    In any case, I'd still like to stay close to Base UI's approach where possible. Reusing Toast directly may require overriding too much of its interaction model, since our notices also cover persistent banners and inline messages. A first-party implementation seems reasonable for that broader scope. We'd need to maintain it and keep it aligned with Base UI's approach in order to offer a consistent experience for the @wordpress/ui package.

    We should also verify our own use cases with screen readers, especially initial content, dynamically added notices, and announcements while focus is inside the list. Base UI's toast behavior is useful guidance, but those cases may need different decisions for notices.

    And we definitely need to discuss / decide exactly what to do around snackbards, since that sounds like an almost perfect fit for the base ui Toast component?

  9. ciampo commented on Oct 16, 2026

    @ciampo
    Contributor

    This issue is technically addressed by #82737; should we repurpose it to official include remaining Notice.List work, or close it and create a new issue?

  10. aduth commented on Oct 16, 2026

    @aduth
    MemberAuthor

    Yes, a new issue makes sense. I'll create one.

  11. aduth commented on Oct 16, 2026

    @aduth
    MemberAuthor

    Follow-up issue at #84941

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

Metadata

Metadata

Assignees

Labels

Needs Accessibility FeedbackNeed input from accessibilityNeeds DecisionNeeds a decision to be actionable or relevant[Package] UI/packages/ui[Status] In ProgressTracking issues with work in progress[Type] TaskIssues or PRs that have been broken down into an individual action to take

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    Sponsor
    SponsoredKunjungi sekarang
    Promo