Skip to content

Commit

Permalink
Docs: forms accessibility cleanup (twbs#31114)
Browse files Browse the repository at this point in the history
* 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 twbs#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 <[email protected]>
  • Loading branch information
2 people authored and olsza committed Oct 3, 2020
1 parent 1c0d380 commit 8936b50
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 28 deletions.
2 changes: 1 addition & 1 deletion site/content/docs/5.0/forms/checks-radios.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
6 changes: 0 additions & 6 deletions site/content/docs/5.0/forms/input-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
8 changes: 0 additions & 8 deletions site/content/docs/5.0/forms/layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down Expand Up @@ -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 >}}
19 changes: 17 additions & 2 deletions site/content/docs/5.0/forms/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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.
24 changes: 13 additions & 11 deletions site/content/docs/5.0/forms/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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">
Expand All @@ -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>
Expand Down

0 comments on commit 8936b50

Please sign in to comment.