accessibility-guidelines

This document is in beta. Help us by reporting issues via Github or email

Back to the overview page

Information and relationships

On this page:


Summary

Make sure that information and relationships that are conveyed visually (like distinct sections within a page, or a label next to a checkbox) are also identified in code.

When content structures like tables, lists, sections and headings are communicated visually, they should also be coded in ways that assistive technologies can understand.


Requirements

Requirements for both native and web

Web only requirements

Why?

This ensures that the structure of the content that’s conveyed visually by the designs is also available to screen reader, screen magnifier and speech recognition tool users.

Here’s a fun video illustrating the difference this makes for screen reader users.

Official wording in the Web Content Accessibility Guidelines

1.3.1 Info and Relationships: Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. (Level A)

See the W3C’s detailed explanation of this guideline with techniques and examples.


Guidance for Design

This section needs more content. Contribute via Github issue or email.

More guidance for design


Guidance for iOS

Setting a view as a heading (e.g. table section headings or screen titles):

headingLabel.isAccessibilityElement = true
headingLabel.accessibilityTraits = [.heading]

Setting a custom view as a search field:

customSearchField.isAccessibilityElement = true
customSearchField.accessibilityTraits = [.searchField]

Setting a custom view as a tab bar:

customTabBar.isAccessibilityElement = true
customTabBar.accessibilityTraits = [.tabBar]

You can combine traits if your element needs it:

view.accessibilityTraits = [.heading, .updatesFrequently]

Providing a label for input fields:

textField.accessibilityLabel = "First Name"

More guidance for iOS


Guidance for Android

Setting a view as a heading (requires API level 28):

view.isAccessibilityHeading = true
<TextView
  ...
  android:accessibilityHeading="true"
  ... />

More guidance for Android


Guidance for Flutter

Flutter deals with assistive technologies like screen readers using the Semantics() widget.

Setting a widget as a heading (e.g. table section headings or screen titles):

For widgets that don’t have this set by default and don’t expose this semantic property you can do this:

Semantics(
  header: true,
  child: HeadingWidget()
)

Setting a custom widget as a search field:

Semantics(
  label: 'Search',
  child: CustomSearchField()
)

Note: if you set textField: true in the Semantics() widget which has a TextField() child then the screen reader will ignore the Semantics() widget and will only use the semantics of TextField().

Setting a custom widget as a tab bar:

The Tab() widget is currently not very accessibility friendly when it comes to text size as its height is set. The use of a custom tab widget is recomended.

class CustomTabWidget extends StatelessWidget {
  const CustomTabWidget({
    Key key,
    this.semanticLabel,
  }) : super(key: key);

  final String semanticLabel;

  @override
  Widget build(BuildContext context) {
    return Semantics( // check the Semantics widget documentation to see what other properties youc could use
      label: semanticLabel,
      child: // construct the rest of your tab here
    );
  }
}

Note: keep in mind that the widgets you use might have their own semantic properties.

Setting a custom widget as a bottom nav bar

The BottomNavigationBar(items:[]) only takes a list of BottomNavigationBarItem so the item widgets cannot be wrapped in a Semantics() widget but their children can.

// Bottom navigation tab with a custom widget instead of icon
BottomNavigationBarItem(
  // Your CustomWidget() could also just have a Semantics() widget inside
  // of its own implementation and expose any property of Semantics() you need
  // this would make the CustomWidget() more reusable and make for cleaner code
  icon: Semantics(
    label: 'CustomWidget Semantic Lable',
    child: CustomWidget(),
  ),
),
// Bottom navigation tab with just a icon
BottomNavigationBarItem(
  icon: Icon(
    Icons.myIcon,
    semanticLabel: 'Icon Semantic label',
  ),
),
// Bottom navigation tab with a icon and text lable
BottomNavigationBarItem(
  icon: Icon(Icons.icon), // icon is a required property
  title: Text(
    'Text',
    semanticsLabel: 'Text Semantic Label',
  ),
),
// If you wish to exlude any default semantics such as the text in a Text() widget you could do this
BottomNavigationBarItem(
  icon: Icon(Icons.image),
  title: ExcludeSemantics(child: Text('Image')),
),
// You can also combine or mix and match all of these together should you need to
BottomNavigationBarItem(
  icon: Icon(
    Icons.format_align_left,
    semanticLabel: 'Icon Semantic label',
  ),
  title: ExcludeSemantics(
    child: Text(
      'Form',
      semanticsLabel: 'Text Semantic Label',
    ),
  ),
),

Dealing with invisible widgets and their semantics:

If you have widgets that you want to exclude from semantics because they serve no purpose for a visually impaired user or if they are hidden until a change of state you can use the ExcludeSemantics() or Semantics(excludeSemantics: bool) as shown below:

ExcludeSemantics(
  child: new Image.asset(ImageAssets.decorativeCandle),
),
// Here we can toggle whether semantics are being excluded with the `excluding: bool` property which is true by default
ExcludeSemantics(
  excluding: bool,
  child: Visibility(
    visible: bool,
    child: SometimesVisibleWidget(),
  ),
)
Semantics(
  excludeSemantics: bool,
  child: SometimesVisibleWidget(),
),

You can combine semantics if your element/widget needs it:

MergeSemantics(
  child: Column(
    children: <Widget>[
        Text('Line one'),
        Text('Line two'),
    ],
  ),
),

Note: this will merge the semantics of the child and its children into one semantic node

Providing a label for input fields:

There are two ways to add a label to the text field both are shown below one of them is the same as setting a custom view as a search field:

Semantics(
  label: 'Search', // this will only add a semantic label to textfield and not a actual visible label
  child: TextField()
)
// OR
TextField(
  decoration: InputDecoration(
    hintText: String, // hint text has its own built in semantics
    labelText: String, // label text has its own builtsemantics
  ),
),

More guidance for Flutter


Guidance for Web

This section needs a review and more content. Contribute or report issues via Github (preferred) or email.

Forming a correct headings structure

<h1>Main heading for the page</h1>

<h2>Heading for the first top level section of the page</h2>
<h3>Heading for a sub-section, nested under the first top level section</h3>
<h4>Heading for a sub-sub-section, nested under that sub-section</h4>

<h2>Heading for the second top level section of the page</h2>
<h3>Heading for a sub-section, nested under the second top level section</h3>

Example: A heading structure for a weather website

<h1>Local Weather</h1>
<h2>Today's Forecast</h2>
<h2>Tomorrow Forecast</h2>
<h3>Tomorrow's Allergy Forecast</h3>
Failure example
<div class="heading">Local Weather</div>
<div class="subheading">Today's Forecast</div>
<div class="subheading">Tomorrow Forecast</div>
<div class="subheading2">Tomorrow's Allergy Forecast</div>

More guidance on forming a correct headings structure

Forming a data table

Example of a basic table structure

<table>
  <caption>
    Short descriptive name for the table
  </caption>

  <thead>
    <tr>
      <th scope="col">Column Heading 1</th>
      <th scope="col">Column Heading 2</th>
      <th scope="col">Column Heading 3</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <th scope="row">Row Heading 1</th>
      <td>Cell value for row 2, column 2</td>
      <td>Cell value for row 2, column 3</td>
    </tr>

    <tr>
      <th scope="row">Row Heading 2</th>
      <td>Cell value for row 3, column 2</td>
      <td>Cell value for row 3, column 3</td>
    </tr>
  </tbody>
</table>

Do not use HTML tables for layout out content

More guidance on forming a data table

Forming lists

Example of an ordered list

<ol>
  <li>List value 1</li>
  <li>List value 2</li>
</ol>

Example of a description list

<dl>
  <dt>Title 1</dt>
  <dd>List value 1</dd>
  <dd>List value 2</dd>
  <dt>Title 2</dt>
  <dd>List value 1</dd>
</dl>

More guidance on forming lists

<label for="first-name">First Name</label> <input name="first-name" />

Common mistakes

Use HTML5 sectioning elements to describe document structure and outline different parts of the page

Element What it means Implicit landmark role
<header> A section of content that is repeated at the top of all/several pages role="banner" if it is a direct child of <body>
<nav> An area containing navigation links role="navigation"
<search> A component that allows users to search content on the site role="search"
<main> The main content of the page (meaning not header, navigation or footer elements or complementary content) role="main"
<form> A form role="form" if it has an Accessible Name
<section> A section of content that you want added in the list of Landmark regions role="region" if it has an Accessible Name
<aside> Content that complements the content in the main area, but would also make sense on its own role="complementary"
<footer> Information about the page (such as copyright) role="contentinfo" if it is a direct child of <body>

Example

<header>
  <div id="logo">...</div>

  <nav aria-label="BBC">
    <ul>
      <li><a href="...">News</a></li>
      <li><a href="...">Weather</a></li>
      <li><a href="...">Sport</a></li>
      <li><a href="...">Travel</a></li>
      ...
    </ul>
  </nav>

  <nav aria-label="News">
    <ul>
      <li><a href="...">Home</a></li>
      <li><a href="...">UK</a></li>
      <li><a href="...">World</a></li>
      <li><a href="...">Business</a></li>
      ...
    </ul>
  </nav>
</header>

<main>
  <h1>Pisa rankings: Why Estonian pupils shine in global tests</h1>

  ...
</main>

<aside>...</aside>

<footer>
  <p>BBC 2016</p>
  <ul>
    ...
  </ul>
</footer>
Failure example
<!-- Do not do this -->
<div id="header">
  <div id="logo">...</div>

  <div id="nav" aria-label="BBC">
    <ul>
      <li><a href="...">News</a></li>
      <li><a href="...">Weather</a></li>
      <li><a href="...">Sport</a></li>
      <li><a href="...">Travel</a></li>
      ...
    </ul>
  </div>

  <div id="nav2" aria-label="News">
    <ul>
      <li><a href="...">Home</a></li>
      <li><a href="...">UK</a></li>
      <li><a href="...">World</a></li>
      <li><a href="...">Business</a></li>
      ...
    </ul>
  </div>
</div>

<div id="content">
  <h1>Pisa rankings: Why Estonian pupils shine in global tests</h1>

  ...
</div>

<div id="related_content">...</div>

<div id="footer">
  <p>BBC 2016</p>
  <ul>
    ...
  </ul>
</div>

More guidance on identifying the page’s landmark areas


More info

Sources

Contribute

This document is in beta. Help us by reporting issues via Github or email