mui / material-ui

Material UI: Comprehensive React component library that implements Google's Material Design. Free forever.
https://mui.com/material-ui/
MIT License
93.71k stars 32.23k forks source link

[Dialog] `DialogTitle` should use h1 instead of h2 #34250

Open paulschreiber opened 2 years ago

paulschreiber commented 2 years ago

Current behavior 😯

Dialog and DialogTitle generates this HTML

<div class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation24 MuiDialog-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm css-1t1j96h-MuiPaper-root-MuiDialog-paper" role="dialog" aria-labelledby=":r3:">
   <h2 class="MuiTypography-root MuiTypography-h6 MuiDialogTitle-root css-bdhsul-MuiTypography-root-MuiDialogTitle-root" id=":r3:">Title</h2>
</div>

Expected behavior πŸ€”

<div class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation24 MuiDialog-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthSm css-1t1j96h-MuiPaper-root-MuiDialog-paper" role="dialog" aria-labelledby=":r3:">
   <h1 class="MuiTypography-root MuiTypography-h6 MuiDialogTitle-root css-bdhsul-MuiTypography-root-MuiDialogTitle-root" id=":r3:">Title</h1>
</div>

Steps to reproduce πŸ•Ή

import React from "react";
import { Dialog, DialogTitle } from "@mui/material";

export default function App() {
  return (
    <>
      <Dialog open={true}>
        <DialogTitle>Title</DialogTitle>
      </Dialog>
    </>
  );
}

Context πŸ”¦

Dialogs should have their owner heading hierarchy, starting with h1. This is important for screen readers.

Your environment 🌎

npx @mui/envinfo ``` System: OS: macOS 12.5.1 Binaries: Node: 18.7.0 - /opt/homebrew/bin/node Yarn: 1.22.19 - /opt/homebrew/bin/yarn npm: 8.15.0 - /opt/homebrew/bin/npm Browsers: Chrome: 105.0.5195.102 Edge: Not Found Firefox: 104.0.1 Safari: 15.6.1 npmPackages: @emotion/react: ^11.10.0 => 11.9.3 @emotion/styled: ^11.10.0 => 11.9.3 @mui/base: 5.0.0-alpha.96 @mui/codemod: 5.10.4 @mui/core-downloads-tracker: 5.10.4 @mui/docs: 5.10.3 @mui/envinfo: 2.0.6 @mui/icons-material: 5.10.3 @mui/joy: 5.0.0-alpha.44 @mui/lab: 5.0.0-alpha.98 @mui/markdown: 5.0.0 @mui/material: 5.10.4 @mui/material-next: 6.0.0-alpha.52 @mui/private-theming: 5.10.3 @mui/styled-engine: 5.10.4 @mui/styled-engine-sc: 5.10.3 @mui/styles: 5.10.3 @mui/system: 5.10.4 @mui/types: 7.2.0 @mui/utils: 5.10.3 @mui/x-data-grid: 5.15.2 @mui/x-data-grid-generator: 5.15.2 @mui/x-data-grid-premium: 5.15.2 @mui/x-data-grid-pro: 5.15.2 @mui/x-date-pickers: 5.0.0-beta.5 @mui/x-date-pickers-pro: 5.0.0-beta.5 @mui/x-license-pro: 5.15.0 @types/react: ^18.0.17 => 18.0.14 react: ^18.2.0 => 18.2.0 react-dom: ^18.2.0 => 18.2.0 styled-components: 5.3.5 typescript: ^4.8.2 => 4.6.4 ```
paulschreiber commented 2 years ago

@hbjORbj please tag with accessibility.

danilo-leal commented 2 years ago

Thanks for the heads up @paulschreiber! I wonder if we really should do this, though. If the dialog's title is an h1, wouldn't that confuse users leaning on screen readers, given that it could give the impression that they have navigated to a different page altogether, which is not totally the case? A few benchmarks I've collected quickly:

oliviertassinari commented 2 years ago

IMHO, this issue is a duplicate of #16569.

Also, +1 to keep h2 until a supporting material is provided to justify why h1 would be better.

jscholes commented 2 years ago

Hello all; for context I represent PAC, the team of accessibility consultants who recommended that this change be made within a product managed by @paulschreiber. Hopefully I can shine a light on this suggestion.

A modal dialog is considered to be a distinct area from the main page, and hence the heading hierarchy can and should be reset. An h2 is not the most appropriate choice, because:

To address the specific question by @danilo-leal:

If the dialog's title is an h1, wouldn't that confuse users leaning on screen readers, given that it could give the impression that they have navigated to a different page altogether ...

I really appreciate the attention to detail and user experience implied by this query. However, screen readers will convey the fact that the user's new context is a modal dialog (assuming that everything else about the dialog is coded correctly). These announcements are quite distinct from those triggered by a page load, and hence there should be no confusion.

In terms of resources, you can observe this recommended approach within a Simple Dialog example from Deque, an Accessible Modal Dialog example by Paul J. Adam, the A11y Dialog library by @KittyGiraudel, among others. The WAI-ARIA Authoring Practices (APG) linked earlier in this thread is not a spec or published standard; they've chosen to be opinionated about the use of an h2 without providing documented justification, and that aspect of their example is not something I agree with.

Hope this helps.

danilo-leal commented 2 years ago

Thanks, @jscholes, appreciate the thorough answer! All of that makes sense to me and seems enough to allow the change to move forward. @oliviertassinari any objections or thoughts? We might want to enrich documentation about this, I think, given that it has come up again.

oliviertassinari commented 2 years ago

I had a look at why it's an h2 in https://www.w3.org/WAI/ARIA/apg/example-index/dialog-modal/dialog.html see https://github.com/w3c/aria-practices/issues/551

Because they are a child window, I have usually recommended a level lower than 1. The lack of a level 1 could actually help some people understand they are not on the main page.

But, I don't think there is any hard and fast rule here. It is one of those subjective calls where there is rationale that could probably justify either approach or a variety of others as well.

I think both can work, I have no specific recommendations.

siriwatknp commented 2 years ago

I think we should have a valid evidence that h1 is better than h2 (maybe a comparison with screen readers), otherwise I don't see why we need to change.

oliviertassinari commented 2 years ago

I asked @xurxe for some perspective on this issue during our last call. It seems that there are use cases for both, so I suspect that updating https://mui.com/base/react-modal/#accessibility with guidelines could be enough to close this issue.

xurxe commented 2 years ago

Hi everyone! I just wanted to hop into this very interesting discussion and add my two cents, as a web developer and IAAP-certified accessibility specialist (CPACC, WAS, CPWA).

TL;DR

Definitions and background

As @jscholes mentioned, we should refer to the applicable spec or standard, which is in this case is ARIA 1.1. There's three key definitions we should look at.

  1. The dialog role

A dialog is a descendant window of the primary window of a web application. [...] Dialogs are most often used to prompt the user to enter or respond to information. A dialog that is designed to interrupt workflow is usually modal.

  1. The window role (since a dialog is a type of window)

Elements with this role have a window-like behavior in a graphical user interface (GUI) context, regardless of whether they are implemented as a native window in the operating system, or merely as a section of the document styled to look like a window.

  1. The aria-modal property

The aria-modal attribute is used to indicate that the presence of a "modal" element precludes usage of other content on the page. For example, when a modal dialog is displayed, it is expected that the user's interaction is limited to the contents of the dialog, until the modal dialog loses focus or is no longer displayed.

In the context of HTML, a dialog is a nested, secondary window that opens up within the page. A dialog can be modal or non-modal i.e. modeless.

A modal dialog or window launches a special mode of operation, during which the user must interact with it in one of the "approved" ways before being allowed to return to the primary window. Such approved ways may or may not include: activating a Close button, entering text into an input field and activating an OK button, etc, depending on the situation.

A non-modal dialog or window does not launch a special mode of operation, and users are free to switch between it and the primary window. These are not so commonly used in web applications, but could be something like... a color utility in an online design application (as long as it actually follows the non-modal dialog pattern, rather that being implemented as a tooltip or something else).

I also want to point out that there is conflation / confusion between dialogs and modal dialogs, both in this discussion and in the MUI Dialog documentation. Additionally, the MUI Modal documentation has some inaccuracies as well. Addressing these issues goes beyond the scope of this discussion, but in spite of that I'd like to say that the MUI Dialog component constitutes a fairly successful implementation of the modal dialog pattern.

My take on the heading level

After much consideration, I do think that h2 is the most appropriate default level for DialogTitle. Here's why:

jscholes commented 2 years ago

@xurxe Thank you for taking the time to write this out. Unfortunately, the conclusions seem to revolve around assertions which themselves are not standardised or evidence-based, rather than on the nuances of end-user and developer experience. Specifically:

A dialog is a descendant window ... Elements with this role have a window-like behavior in a graphical user interface (GUI) context ... The aria-modal attribute is used to indicate that the presence of a "modal" element precludes usage of other content on the page.

In other words: what we have is a window on top of some other content, which precludes access to that content, and should be treated as a separate bounded context. The window is a descendant, but this is mostly a technical concern, and only relevant to users from a wayfinding perspective as they navigate into and out of the dialog. Note that I'm only considering modal dialogs here; non-modal dialogs are a completely separate topic and not in scope.

However, you then assert that:

There should only be one h1 per page.

For the purposes of usability and structured understanding, there should only be a single h1 per user-addressable area of a web application. When a dialog is modal, that should be the sole area of the page that the user is able to reach, and hence the presence of multiple h1s is irrelevant.

This is also why each dialog doesn't need to have a uniquely named "Close" button, for example, because the user should never be interacting with multiple modals at once. Suggesting that every modal dialog must participate in the same constraints as the parent page is not scalable nor user-friendly.

A dialog is a secondary window within the main web page / window / application. As such, it makes sense that it's part of its heading hierarchy, and h2 is the most sensible level in most situations.

I've already covered why I believe the first part of this statement, about the participation of the modal content within the parent page's constraints, to be suboptimal. However, I want to call out the following suggestion:

... h2 is the most sensible level in most situations

... as something which I don't understand. When developing a heading hierarchy that truly reflects the structure of the underlying content architecture, the most sensible heading level will differ based on context. There is no such thing as a heading level which is the "most sensible level in most situations".

To follow this logic through to its conclusion, though: if a modal dialog does need to participate in the page's overall hierarchy, why is hardcoding an h2 appropriate? Should the dialog title not use a heading level that causes it to slot into the parent section that invoked it? For example, if there is a section headed at level 3, and a button in that section invokes a modal, h4 is the most logical level, not h2.

To be clear, I'm not suggesting that this should be the case; I think I've been pretty unambiguous up to this point about my support for an h1. But it's important to explore the reasoning behind nobody following this seemingly logical pattern that I've outlined, and that's because the outcome is a confusing one for users and developers alike. It would act as an extremely limiting factor given that there are only six heading levels available, and again, would be confusing for users because they couldn't locate the parent headings anyway.

So, with that in mind, I'm struggling to see h2 as more appropriate than h1, rather than just an arbitrary choice.

Encountering a new h1 is typically an indication that the page has changed.

I'm not sure what you're basing this on, but the primary indication that the page has changed is a new page title, which in a standard multi-page app is announced by a screen reader automatically. The h1 is often a way down the page, at the start of the main content, and hence is not spoken automatically right away (if at all).

Similarly, when a dialog is invoked, and focus is placed e.g. on the "Close" button, a screen reader will inform the user of that context. They will know that they are inside a dialog, assuming that it is named and marked up correctly, and the h1 should then match the accessible name on the modal dialog container.

if the need truly arises, it's possible to use aria-level to create the equivalents of h7, h8, etc.

In theory, yes. In reality, most screen reader/browser combinations don't support this approach, and will either fall back to h6 or h2 when aria-level=">7" is encountered. Even if they do convey the heading level as 7 or above, there are no quick navigation keystrokes to jump to those heading levels specifically, and hence this approach must never be suggested, let alone encouraged.

I don't think it should make any difference as to whether or not my advice is taken on board. But for what it's worth, I speak not only as an accessibility professional, but a screen reader user myself.

I've enumerated my reasoning twice at this point, but in essence we have a 50/50 split between two people working in the accessibility industry. I will continue to advise clients to use an h1 for their dialog titles, including in the specific case that caused this bug to be filed, and I remain available to answer additional questions.

xurxe commented 2 years ago

Thanks @jscholes for your thoughtful reply!

What I understand from this conversation is that we both agree on our interpretation of ARIA 1.1 (side note: when I quoted the spec it was just for the benefit of the non-specialists reading, since I gathered you were already familiar with it), but we have different opinions regarding what's not directly said in the ARIA or HTML specs, especially in terms of how a modal dialog relates to the primary window / application. And it seems like we're not alone in that, judging by the different implementation examples that have been discussed in this thread.

I also wasn't very clear on what I meant by "h2 is the most sensible level in most situations" (thanks for pointing that out!). What I was trying to say that, in most instances of modal dialogs I've personally implemented or evaluated, I saw their content as something that is part of the main window, but at quite a high level (i.e. not deeply nested). Some examples:

In most examples I could think of, if I was to use a heading element at all, I would have chosen h2.

I did however come up with some cases where I could see a lot of value in using h1 instead. One example would be a modal dialog requiring the user to confirm that they're over 18 in order to access, let's say, a gambling website. In that case, assuming that the dialog is automatically open when the user accesses the site for the first time and that the answer will be stored so that the dialog won't be shown in subsequent visits, it feels more intuitive to me that the heading on that modal would be h1.

I think a reasonable compromise would be to let developers customize the level of DialogTitle. Of course, a default level would still have to be chosen. I think the default should be h2, you think it should be h1; both options have their own logic that makes internal sense, and I ultimately don't think that either one would be incorrect :)

abdermaiza commented 10 months ago

Bootstrap had the same conversation, and the a11y expert (Patrick H. Lauke) said that a H1 for a modal title should be the best: "as modal dialogs create their own little world/document/structure, it would make sense that the title is the primary heading in this new "island" of content. particularly if the underlying page is hidden from AT"...

https://github.com/twbs/bootstrap/issues/37179

Thanks!