]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
Docs: forms accessibility cleanup (#31114)
authorPatrick H. Lauke <redux@splintered.co.uk>
Sat, 11 Jul 2020 20:38:43 +0000 (21:38 +0100)
committerGitHub <noreply@github.com>
Sat, 11 Jul 2020 20:38:43 +0000 (21:38 +0100)
* Expand on disabled fieldsets and faked buttons

include further advice/information on how to disable faked buttons for keyboard/AT users

* Centralise accessible name advice in forms overview

seems odd to only mention (separately) label, aria-label etc in input-group and layout. the advice is just as pertinent in other sections like select. checks only skims over this.

moving this, in expanded form, into the overview section itself. adding a specific cross-reference (just because they are easily left with no accname at all) in the checks page.

* Change warning about accessibility, modify server-side example

- paradoxically, due to our current problems with validation (see #28414) and the fact that browsers seem to have improved in this area for the most part, it's now actually better to use browser-native validation
- added explicit `id` and `aria-describedby` association to at least the server-side form error messages, to show how it should be done properly, and expanded the prose for that explaining this.

* Replace `.sr-only` with `.visually-hidden` in new addition

* Copy edits for clarity in parenthetical

* Copy and formatting tweaks

- Wordsmithing here and there
- Turns some hyphens into em dashes
- Turns a long running comma separated list into an unordered list
- Rearranges some copy just a bit

Co-authored-by: Mark Otto <markd.otto@gmail.com>
site/content/docs/5.0/forms/checks-radios.md
site/content/docs/5.0/forms/input-group.md
site/content/docs/5.0/forms/layout.md
site/content/docs/5.0/forms/overview.md
site/content/docs/5.0/forms/validation.md

index c8d59e3cfd258e7ab66f937f2cc4277772351136..b6914ee42dc6305c8933b07dd0f0406ff49c3377 100644 (file)
@@ -199,7 +199,7 @@ Group checkboxes or radios on the same horizontal row by adding `.form-check-inl
 
 ## Without labels
 
-Omit the wrapping `.form-check` for checkboxes and radios that have no label text. Remember to still provide some form of label for assistive technologies (for instance, using `aria-label`).
+Omit the wrapping `.form-check` for checkboxes and radios that have no label text. Remember to still provide some form of accessible name for assistive technologies (for instance, using `aria-label`). See the [forms overview accessibility]({{< docsref "/forms/overview#accessibility" >}}) section for details.
 
 {{< example >}}
 <div>
index 3ec1f6cb045b849bfa573946d3fa3452eb6b4af4..599fdbacde1e0e38cc13f9268e54c4c38f68ece9 100644 (file)
@@ -326,9 +326,3 @@ Input groups include support for custom selects and custom file inputs. Browser
   <button class="btn btn-outline-secondary" type="button" id="inputGroupFileAddon04">Button</button>
 </div>
 {{< /example >}}
-
-## Accessibility
-
-Screen readers will have trouble with your forms if you don't include a label for every input. For these input groups, ensure that any additional label or functionality is conveyed to assistive technologies.
-
-The exact technique to be used (`<label>` elements hidden using the `.visually-hidden` class, or use of the `aria-label` and `aria-labelledby` attributes, possibly in combination with `aria-describedby`) and what additional information will need to be conveyed will vary depending on the exact type of interface widget you're implementing. The examples in this section provide a few suggested, case-specific approaches.
index 9b63d3202b7e47396ae1d91b15bf314337e34881..84944b986c61949b7df59bdd5a3a1b06ff8a6ab6 100644 (file)
@@ -297,8 +297,6 @@ You can then remix that once again with size-specific column classes.
 
 Use the `.col-auto` class to create horizontal layouts. By adding [gutter modifier classes]({{< docsref "/layout/gutters" >}}), we'll have gutters in horizontal and vertical directions. The `.align-items-center` aligns the form elements to the middle, making the `.form-checkbox` align properly.
 
-Be sure to always include a `<label>` with each form control, even if you need to visually hide it with `.visually-hidden` (which still keeps it available to assistive technologies such as screen readers).
-
 {{< example >}}
 <form class="row row-cols-lg-auto g-3 align-items-center">
   <div class="col-12">
@@ -333,9 +331,3 @@ Be sure to always include a `<label>` with each form control, even if you need t
   </div>
 </form>
 {{< /example >}}
-
-{{< callout warning >}}
-### Alternatives to hidden labels
-
-Assistive technologies such as screen readers will have trouble with your forms if you don't include a label for every input. For these inline forms, you can hide the labels using the `.visually-hidden` class. There are further alternative methods of providing a label for assistive technologies, such as the `aria-label`, `aria-labelledby` or `title` attribute. If none of these are present, assistive technologies may resort to using the `placeholder` attribute, if present, but note that use of `placeholder` as a replacement for other labeling methods is not advised.
-{{< /callout >}}
index 1eb4cce5942bb1c6845a2ad50eea3e2d15d24c7d..a181c34dd4773d35feb4b8d7d948d710e657404e 100644 (file)
@@ -97,9 +97,9 @@ Add the `disabled` boolean attribute on an input to prevent user interactions an
 <input class="form-control" id="disabledInput" type="text" placeholder="Disabled input here..." disabled>
 {{< /highlight >}}
 
-Add the `disabled` attribute to a `<fieldset>` to disable all the controls within.
+Add the `disabled` attribute to a `<fieldset>` to disable all the controls within. Browsers treat all native form controls (`<input>`, `<select>`, and `<button>` elements) inside a `<fieldset disabled>` as disabled, preventing both keyboard and mouse interactions on them.
 
-By default, browsers will treat all native form controls (`<input>`, `<select>`, and `<button>` elements) inside a `<fieldset disabled>` as disabled, preventing both keyboard and mouse interactions on them. However, if your form also includes `<a ... class="btn btn-*">` elements, these will only be given a style of `pointer-events: none`.
+However, if your form also includes custom button-like elements such as `<a class="btn btn-*">...</a>`, these will only be given a style of `pointer-events: none`, meaning they are still focusable and operable using the keyboard. In this case, you must manually modify these controls by adding `tabindex="-1"` to prevent them from receiving focus and `aria-disabled="disabled"` to signal their state to assistive technologies.
 
 {{< example >}}
 <form>
@@ -126,3 +126,18 @@ By default, browsers will treat all native form controls (`<input>`, `<select>`,
   </fieldset>
 </form>
 {{< /example >}}
+
+## Accessibility
+
+Ensure that all form controls have an appropriate accessible name so that their purpose can be conveyed to users of assistive technologies. The simplest way to achieve this is to use a `<label>` element, or—in the case of buttons—to include sufficiently descriptive text as part of the `<button>...</button>` content.
+
+For situations where it's not possible to include a visible `<label>` or appropriate text content, there are alternative ways of still providing an accessible name, such as:
+
+- `<label>` elements hidden using the `.visually-hidden` class
+- Pointing to an existing element that can act as a label using `aria-labelledby`
+- Providing a `title` attribute
+- Explicitly setting the accessible name on an element using `aria-label`
+
+If none of these are present, assistive technologies may resort to using the `placeholder` attribute as a fallback for the accessible name on `<input>` and `<textarea>` elements. The examples in this section provide a few suggested, case-specific approaches.
+
+While using visually hidden content (`.visually-hidden`, `aria-label`, and even `placeholder` content, which disappears once a form field has content) will benefit assistive technology users, a lack of visible label text may still be problematic for certain users. Some form of visible label is generally the best approach, both for accessibility and usability.
index d70507037bc10427444a7b3753570db995ee29a4..d9c0666aa145d6b38a10e78ccded6fc6974db07e 100644 (file)
@@ -10,7 +10,7 @@ extra_js:
 ---
 
 {{< callout warning >}}
-We currently recommend using custom validation styles, as native browser default validation messages are not consistently exposed to assistive technologies in all browsers (most notably, Chrome on desktop and mobile).
+We are aware that currently the client-side custom validation styles and tooltips are not accessible, since they are not exposed to assistive technologies. While we work on a solution, we'd recommend either using the server-side option or the default browser validation method.
 {{< /callout >}}
 
 ## How it works
@@ -163,6 +163,8 @@ While these feedback styles cannot be styled with CSS, you can still customize t
 
 We recommend using client-side validation, but in case you require server-side validation, you can indicate invalid and valid form fields with `.is-invalid` and `.is-valid`. Note that `.invalid-feedback` is also supported with these classes.
 
+For invalid fields, ensure that the invalid feedback/error message is associated with the relevant form field using `aria-describedby` (noting that this attribute allows more than one `id` to be referenced, in case the field already points to additional form text).
+
 {{< example >}}
 <form class="row g-3">
   <div class="col-md-4">
@@ -183,43 +185,43 @@ We recommend using client-side validation, but in case you require server-side v
     <label for="validationServerUsername" class="form-label">Username</label>
     <div class="input-group">
       <span class="input-group-text" id="inputGroupPrepend3">@</span>
-      <input type="text" class="form-control is-invalid" id="validationServerUsername" aria-describedby="inputGroupPrepend3" required>
-      <div class="invalid-feedback">
+      <input type="text" class="form-control is-invalid" id="validationServerUsername" aria-describedby="inputGroupPrepend3 validationServerUsernameFeedback" required>
+      <div id="validationServerUsernameFeedback" class="invalid-feedback">
         Please choose a username.
       </div>
     </div>
   </div>
   <div class="col-md-6">
     <label for="validationServer03" class="form-label">City</label>
-    <input type="text" class="form-control is-invalid" id="validationServer03" required>
-    <div class="invalid-feedback">
+    <input type="text" class="form-control is-invalid" id="validationServer03" aria-describedby="validationServer03Feedback" required>
+    <div id="validationServer03Feedback" class="invalid-feedback">
       Please provide a valid city.
     </div>
   </div>
   <div class="col-md-3">
     <label for="validationServer04" class="form-label">State</label>
-    <select class="form-select is-invalid" id="validationServer04" required>
+    <select class="form-select is-invalid" id="validationServer04" aria-describedby="validationServer04Feedback" required>
       <option selected disabled value="">Choose...</option>
       <option>...</option>
     </select>
-    <div class="invalid-feedback">
+    <div id="validationServer04Feedback" class="invalid-feedback">
       Please select a valid state.
     </div>
   </div>
   <div class="col-md-3">
     <label for="validationServer05" class="form-label">Zip</label>
-    <input type="text" class="form-control is-invalid" id="validationServer05" required>
-    <div class="invalid-feedback">
+    <input type="text" class="form-control is-invalid" id="validationServer05" aria-describedby="validationServer05Feedback" required>
+    <div id="validationServer05Feedback" class="invalid-feedback">
       Please provide a valid zip.
     </div>
   </div>
   <div class="col-12">
     <div class="form-check">
-      <input class="form-check-input is-invalid" type="checkbox" value="" id="invalidCheck3" required>
+      <input class="form-check-input is-invalid" type="checkbox" value="" id="invalidCheck3" aria-describedby="invalidCheck3Feedback" required>
       <label class="form-check-label" for="invalidCheck3">
         Agree to terms and conditions
       </label>
-      <div class="invalid-feedback">
+      <div id="invalidCheck3Feedback" class="invalid-feedback">
         You must agree before submitting.
       </div>
     </div>