diff --git a/docs/devupdate.md b/docs/devupdate.md index 4b3df850c..33dd781f4 100644 --- a/docs/devupdate.md +++ b/docs/devupdate.md @@ -28,3 +28,21 @@ The `moodle_page` class now includes `set_supplementary_content()` and `get_supp For instance, `mod_forum` uses this new mechanism to display a "Go to all discussions" link in the sticky footer when viewing an individual discussion. For more information, see the [Adding supplementary content to the sticky footer](./apis/plugintypes/format/linear_navigation.md#adding-supplementary-content-to-the-sticky-footer) section. + +## Modal dialogue titles are now `

` elements + + + +The title rendered by the `core/modal` template is now an `
`, so that opening a dialogue no longer breaks the page's heading hierarchy for assistive technology users. The title's appearance is unchanged, because its size is now set by the `fs-5` utility class rather than by the element. + +If your plugin renders headings inside dialogue content, they must be nested beneath this `

`, so the first level available to you is `

`. Headings that previously nested beneath the old `

` will now skip levels. This includes content that is rendered into a dialogue without being authored as part of one -- for example, the Markdown headings in an activity module's `modulename_help` string, which core has lowered from `######` to `####` for this reason. + +If your plugin renders its own modal header markup, or overrides the `header` block of the `core/modal` template, apply the same `
+``` + +The level is deliberately fixed at `

`. A dialogue can be opened from anywhere in a page, so it cannot know what the surrounding heading structure is, and the page behind it already provides the single `

`. Placing the title at level 2 keeps it directly beneath that `

` wherever the dialogue is opened from. + +Its appearance comes from the `fs-5` [Bootstrap font size utility class](https://getbootstrap.com/docs/5.3/utilities/text/#font-size), not from the element. Never change the heading element to make a title look bigger or smaller -- change the utility class. + +:::info[Why `

` and not `

`?] + +[Bootstrap's own documentation](https://getbootstrap.com/docs/5.3/components/modal/) uses an `

` for the modal title, on the basis that a dialogue is its own document context. Moodle uses an `

` instead because the page behind the dialogue already has an `

`, and accessibility auditing tools commonly report a second `

` as a failure. + +::: + +### Headings within a dialogue {/* #headings-within-a-dialogue */} + +Because the title is an `

`, the first heading level available to you inside the body or footer of a dialogue is `

`: + +```mustache title="mod/example/templates/my_modal.mustache" +{{< core/modal }} + {{$title}}{{#str}} pluginname, mod_example {{/str}}{{/title}} + {{$body}} +

{{#str}} settings, mod_example {{/str}}

+ {{! ... }} +

{{#str}} advancedsettings, mod_example {{/str}}

+ {{! ... }} + {{/body}} +{{/ core/modal }} +``` + +Skipping a level -- going straight from the `

` title to an `

`, for example -- breaks the heading hierarchy that assistive technology users rely on to navigate the dialogue. See the [heading requirements](/general/development/process/peer-review/accessibility-checklist#page-headers-and-title) in the accessibility peer review checklist. + +This applies to content that is rendered *into* a dialogue as much as to the dialogue's own template. If a language string, filter, or renderer emits headings, and that output can be displayed in a dialogue, its heading levels must fit beneath the `

` title too. The `modulename_help` strings shown by the activity chooser are one example: their Markdown headings start at `####` (`

`) so that they nest correctly under the activity name. + +:::tip[Sizing nested headings] + +If a nested heading needs to look smaller than its level implies, apply an `fs-*` utility class, or set the size in your theme's SCSS. Choose the heading element for its meaning and the class for its appearance. + +::: + +### Overriding the header {/* #overriding-the-header */} + +The `core/modal` template exposes a `header` block, which replaces the whole `modal-header` region including the title element. If you override it, you must render your own heading and it must keep the same level, id, and `modal-title` class, otherwise the dialogue loses the accessible name that `aria-labelledby` points at: + +```mustache title="Overriding the header block" +{{< core/modal }} + {{$header}} +

+ {{! Any additional header content. }} + {{/header}} +{{/ core/modal }} +``` + +In most cases you should override the `title` block instead, and leave the heading itself to `core/modal`. + +:::note[Dialogues that are not built with `core/modal`] + +Some dialogue-like components render their own `modal-header` markup rather than extending `core/modal` -- `tool_usertours` tour steps are one example in core. These follow the same rule: the title is an `

`. + +::: + +### Testing the heading structure {/* #testing-the-heading-structure */} + +The `best-practice` axe ruleset checks heading order, so an `@accessibility` Behat scenario is the simplest way to guard the structure of a dialogue: + +```gherkin +@accessibility +Scenario: The example dialogue has a valid heading structure + Given I open the example dialogue + Then the "Example dialogue" "dialogue" should meet accessibility standards with "best-practice" extra tests +``` + +Assert on the semantics rather than the presentation. `"h2.modal-title" "css_element"` is a stable assertion; including the `fs-5` utility class in the selector is not, because the class that sets the title's size may change. + +See [Accessibility testing](/general/development/policies/accessibility/testing) for more on writing accessibility tests. + +:::note[Earlier releases] + +Before [MDL-75699](https://tracker.moodle.org/browse/MDL-75699) the dialogue title was an `

`, and headings inside a dialogue were expected to nest beneath that. If you are writing code that must also run on releases from before that fix, be aware that the same markup produces a different heading hierarchy there. + +::: + ## Creating a custom modal type {/* #creating-a-custom-modal-type */} In some situations it is desirable to write a brand new modal. diff --git a/versioned_docs/version-4.5/guides/javascript/modal/index.md b/versioned_docs/version-4.5/guides/javascript/modal/index.md index b79eaf999..4ad4221d0 100644 --- a/versioned_docs/version-4.5/guides/javascript/modal/index.md +++ b/versioned_docs/version-4.5/guides/javascript/modal/index.md @@ -218,6 +218,94 @@ export const init = async () => { +## Heading structure {/* #heading-structure */} + +The `core/modal` template renders the dialogue title as a level 2 heading: + +```mustache title="The title element in core/modal" +
+``` + +The level is deliberately fixed at `

`. A dialogue can be opened from anywhere in a page, so it cannot know what the surrounding heading structure is, and the page behind it already provides the single `

`. Placing the title at level 2 keeps it directly beneath that `

` wherever the dialogue is opened from. + +Its appearance comes from the `h5` [Bootstrap typography utility class](https://getbootstrap.com/docs/4.6/content/typography/), not from the element. Never change the heading element to make a title look bigger or smaller -- change the utility class. + +:::info[Why `

` and not `

`?] + +[Bootstrap 4's own example](https://getbootstrap.com/docs/4.6/components/modal/) uses an `

` for the modal title, which is where Moodle's original markup came from -- it picks the element for its size rather than for its place in the document. Bootstrap 5 corrected this to an `

`, on the basis that a dialogue is its own document context. Moodle uses an `

` instead, because the page behind the dialogue already has an `

`, and accessibility auditing tools commonly report a second `

` as a failure. + +::: + +### Headings within a dialogue {/* #headings-within-a-dialogue */} + +Because the title is an `

`, the first heading level available to you inside the body or footer of a dialogue is `

`: + +```mustache title="mod/example/templates/my_modal.mustache" +{{< core/modal }} + {{$title}}{{#str}} pluginname, mod_example {{/str}}{{/title}} + {{$body}} +

{{#str}} settings, mod_example {{/str}}

+ {{! ... }} +

{{#str}} advancedsettings, mod_example {{/str}}

+ {{! ... }} + {{/body}} +{{/ core/modal }} +``` + +Skipping a level -- going straight from the `

` title to an `

`, for example -- breaks the heading hierarchy that assistive technology users rely on to navigate the dialogue. See the [heading requirements](/general/development/process/peer-review/accessibility-checklist#page-headers-and-title) in the accessibility peer review checklist. + +This applies to content that is rendered *into* a dialogue as much as to the dialogue's own template. If a language string, filter, or renderer emits headings, and that output can be displayed in a dialogue, its heading levels must fit beneath the `

` title too. + +:::tip[Sizing nested headings] + +If a nested heading needs to look smaller than its level implies, apply a heading utility class such as `h6`, or set the size in your theme's SCSS. Choose the heading element for its meaning and the class for its appearance. + +::: + +### Overriding the header {/* #overriding-the-header */} + +The `core/modal` template exposes a `header` block, which replaces the whole `modal-header` region including the title element. If you override it, you must render your own heading and it must keep the same level, id, and `modal-title` class, otherwise the dialogue loses the accessible name that `aria-labelledby` points at: + +```mustache title="Overriding the header block" +{{< core/modal }} + {{$header}} +

+ {{! Any additional header content. }} + {{/header}} +{{/ core/modal }} +``` + +In most cases you should override the `title` block instead, and leave the heading itself to `core/modal`. + +:::note[Dialogues that are not built with `core/modal`] + +Some dialogue-like components render their own `modal-header` markup rather than extending `core/modal` -- `tool_usertours` tour steps are one example in core. These follow the same rule: the title is an `

`. + +::: + +### Testing the heading structure {/* #testing-the-heading-structure */} + +The `best-practice` axe ruleset checks heading order, so an `@accessibility` Behat scenario is the simplest way to guard the structure of a dialogue: + +```gherkin +@accessibility +Scenario: The example dialogue has a valid heading structure + Given I open the example dialogue + Then the "Example dialogue" "dialogue" should meet accessibility standards with "best-practice" extra tests +``` + +Assert on the semantics rather than the presentation. `"h2.modal-title" "css_element"` is a stable assertion; including the `h5` utility class in the selector is not, because the class that sets the title's size may change. + +See [Accessibility testing](/general/development/policies/accessibility/testing) for more on writing accessibility tests. + +:::note[Earlier releases] + +Before [MDL-75699](https://tracker.moodle.org/browse/MDL-75699) the dialogue title was an `

`, and headings inside a dialogue were expected to nest beneath that. If you are writing code that must also run on releases from before that fix, be aware that the same markup produces a different heading hierarchy there. + +::: + ## Creating a custom modal type {/* #creating-a-custom-modal-type */} In some situations it is desirable to write a brand new modal. diff --git a/versioned_docs/version-5.1/guides/javascript/modal/index.md b/versioned_docs/version-5.1/guides/javascript/modal/index.md index b79eaf999..433f4a1e6 100644 --- a/versioned_docs/version-5.1/guides/javascript/modal/index.md +++ b/versioned_docs/version-5.1/guides/javascript/modal/index.md @@ -218,6 +218,94 @@ export const init = async () => { +## Heading structure {/* #heading-structure */} + +The `core/modal` template renders the dialogue title as a level 2 heading: + +```mustache title="The title element in core/modal" +
+``` + +The level is deliberately fixed at `

`. A dialogue can be opened from anywhere in a page, so it cannot know what the surrounding heading structure is, and the page behind it already provides the single `

`. Placing the title at level 2 keeps it directly beneath that `

` wherever the dialogue is opened from. + +Its appearance comes from the `fs-5` [Bootstrap font size utility class](https://getbootstrap.com/docs/5.3/utilities/text/#font-size), not from the element. Never change the heading element to make a title look bigger or smaller -- change the utility class. + +:::info[Why `

` and not `

`?] + +[Bootstrap's own documentation](https://getbootstrap.com/docs/5.3/components/modal/) uses an `

` for the modal title, on the basis that a dialogue is its own document context. Moodle uses an `

` instead because the page behind the dialogue already has an `

`, and accessibility auditing tools commonly report a second `

` as a failure. + +::: + +### Headings within a dialogue {/* #headings-within-a-dialogue */} + +Because the title is an `

`, the first heading level available to you inside the body or footer of a dialogue is `

`: + +```mustache title="mod/example/templates/my_modal.mustache" +{{< core/modal }} + {{$title}}{{#str}} pluginname, mod_example {{/str}}{{/title}} + {{$body}} +

{{#str}} settings, mod_example {{/str}}

+ {{! ... }} +

{{#str}} advancedsettings, mod_example {{/str}}

+ {{! ... }} + {{/body}} +{{/ core/modal }} +``` + +Skipping a level -- going straight from the `

` title to an `

`, for example -- breaks the heading hierarchy that assistive technology users rely on to navigate the dialogue. See the [heading requirements](/general/development/process/peer-review/accessibility-checklist#page-headers-and-title) in the accessibility peer review checklist. + +This applies to content that is rendered *into* a dialogue as much as to the dialogue's own template. If a language string, filter, or renderer emits headings, and that output can be displayed in a dialogue, its heading levels must fit beneath the `

` title too. + +:::tip[Sizing nested headings] + +If a nested heading needs to look smaller than its level implies, apply an `fs-*` utility class, or set the size in your theme's SCSS. Choose the heading element for its meaning and the class for its appearance. + +::: + +### Overriding the header {/* #overriding-the-header */} + +The `core/modal` template exposes a `header` block, which replaces the whole `modal-header` region including the title element. If you override it, you must render your own heading and it must keep the same level, id, and `modal-title` class, otherwise the dialogue loses the accessible name that `aria-labelledby` points at: + +```mustache title="Overriding the header block" +{{< core/modal }} + {{$header}} +

+ {{! Any additional header content. }} + {{/header}} +{{/ core/modal }} +``` + +In most cases you should override the `title` block instead, and leave the heading itself to `core/modal`. + +:::note[Dialogues that are not built with `core/modal`] + +Some dialogue-like components render their own `modal-header` markup rather than extending `core/modal` -- `tool_usertours` tour steps are one example in core. These follow the same rule: the title is an `

`. + +::: + +### Testing the heading structure {/* #testing-the-heading-structure */} + +The `best-practice` axe ruleset checks heading order, so an `@accessibility` Behat scenario is the simplest way to guard the structure of a dialogue: + +```gherkin +@accessibility +Scenario: The example dialogue has a valid heading structure + Given I open the example dialogue + Then the "Example dialogue" "dialogue" should meet accessibility standards with "best-practice" extra tests +``` + +Assert on the semantics rather than the presentation. `"h2.modal-title" "css_element"` is a stable assertion; including the `fs-5` utility class in the selector is not, because the class that sets the title's size may change. + +See [Accessibility testing](/general/development/policies/accessibility/testing) for more on writing accessibility tests. + +:::note[Earlier releases] + +Before [MDL-75699](https://tracker.moodle.org/browse/MDL-75699) the dialogue title was an `

`, and headings inside a dialogue were expected to nest beneath that. If you are writing code that must also run on releases from before that fix, be aware that the same markup produces a different heading hierarchy there. + +::: + ## Creating a custom modal type {/* #creating-a-custom-modal-type */} In some situations it is desirable to write a brand new modal. diff --git a/versioned_docs/version-5.2/guides/javascript/modal/index.md b/versioned_docs/version-5.2/guides/javascript/modal/index.md index b79eaf999..30ee7b4e4 100644 --- a/versioned_docs/version-5.2/guides/javascript/modal/index.md +++ b/versioned_docs/version-5.2/guides/javascript/modal/index.md @@ -218,6 +218,94 @@ export const init = async () => { +## Heading structure {/* #heading-structure */} + +The `core/modal` template renders the dialogue title as a level 2 heading: + +```mustache title="The title element in core/modal" +
+``` + +The level is deliberately fixed at `

`. A dialogue can be opened from anywhere in a page, so it cannot know what the surrounding heading structure is, and the page behind it already provides the single `

`. Placing the title at level 2 keeps it directly beneath that `

` wherever the dialogue is opened from. + +Its appearance comes from the `fs-5` [Bootstrap font size utility class](https://getbootstrap.com/docs/5.3/utilities/text/#font-size), not from the element. Never change the heading element to make a title look bigger or smaller -- change the utility class. + +:::info[Why `

` and not `

`?] + +[Bootstrap's own documentation](https://getbootstrap.com/docs/5.3/components/modal/) uses an `

` for the modal title, on the basis that a dialogue is its own document context. Moodle uses an `

` instead because the page behind the dialogue already has an `

`, and accessibility auditing tools commonly report a second `

` as a failure. + +::: + +### Headings within a dialogue {/* #headings-within-a-dialogue */} + +Because the title is an `

`, the first heading level available to you inside the body or footer of a dialogue is `

`: + +```mustache title="mod/example/templates/my_modal.mustache" +{{< core/modal }} + {{$title}}{{#str}} pluginname, mod_example {{/str}}{{/title}} + {{$body}} +

{{#str}} settings, mod_example {{/str}}

+ {{! ... }} +

{{#str}} advancedsettings, mod_example {{/str}}

+ {{! ... }} + {{/body}} +{{/ core/modal }} +``` + +Skipping a level -- going straight from the `

` title to an `

`, for example -- breaks the heading hierarchy that assistive technology users rely on to navigate the dialogue. See the [heading requirements](/general/development/process/peer-review/accessibility-checklist#page-headers-and-title) in the accessibility peer review checklist. + +This applies to content that is rendered *into* a dialogue as much as to the dialogue's own template. If a language string, filter, or renderer emits headings, and that output can be displayed in a dialogue, its heading levels must fit beneath the `

` title too. The `modulename_help` strings shown by the activity chooser are one example: their Markdown headings start at `####` (`

`) so that they nest correctly under the activity name. + +:::tip[Sizing nested headings] + +If a nested heading needs to look smaller than its level implies, apply an `fs-*` utility class, or set the size in your theme's SCSS. Choose the heading element for its meaning and the class for its appearance. + +::: + +### Overriding the header {/* #overriding-the-header */} + +The `core/modal` template exposes a `header` block, which replaces the whole `modal-header` region including the title element. If you override it, you must render your own heading and it must keep the same level, id, and `modal-title` class, otherwise the dialogue loses the accessible name that `aria-labelledby` points at: + +```mustache title="Overriding the header block" +{{< core/modal }} + {{$header}} +

+ {{! Any additional header content. }} + {{/header}} +{{/ core/modal }} +``` + +In most cases you should override the `title` block instead, and leave the heading itself to `core/modal`. + +:::note[Dialogues that are not built with `core/modal`] + +Some dialogue-like components render their own `modal-header` markup rather than extending `core/modal` -- `tool_usertours` tour steps are one example in core. These follow the same rule: the title is an `

`. + +::: + +### Testing the heading structure {/* #testing-the-heading-structure */} + +The `best-practice` axe ruleset checks heading order, so an `@accessibility` Behat scenario is the simplest way to guard the structure of a dialogue: + +```gherkin +@accessibility +Scenario: The example dialogue has a valid heading structure + Given I open the example dialogue + Then the "Example dialogue" "dialogue" should meet accessibility standards with "best-practice" extra tests +``` + +Assert on the semantics rather than the presentation. `"h2.modal-title" "css_element"` is a stable assertion; including the `fs-5` utility class in the selector is not, because the class that sets the title's size may change. + +See [Accessibility testing](/general/development/policies/accessibility/testing) for more on writing accessibility tests. + +:::note[Earlier releases] + +Before [MDL-75699](https://tracker.moodle.org/browse/MDL-75699) the dialogue title was an `

`, and headings inside a dialogue were expected to nest beneath that. If you are writing code that must also run on releases from before that fix, be aware that the same markup produces a different heading hierarchy there. + +::: + ## Creating a custom modal type {/* #creating-a-custom-modal-type */} In some situations it is desirable to write a brand new modal.