Search code examples
accessibilityscreen-readersnvdawcag2.0

Why when navigating through the header with the screen reader the upper header buttons are always read?


My problem is that i'm trying to make some tables more accessible, but i have encountered a really weird problem that i have tried several solutions but to no avail. I have this table from this screenshot:

Table with problems

As you can see, when i'm going through on each header like CSLO, Start Date, etc, it reads the header from above. So therefore every time i focus either with tab or arrow controls on any header name, it will also read the two buttons from above.

I have tried making the buttons separate, using different roles, taking out classes, etc but i really haven't pinpointed why does it always triggers the buttons even though they are not focused.

The code for it goes like this:

<table
  class="table table-bordered table-hover component-editable slolisting dataTable ui-sortable"
  data-editable-id="slo-list-237"
  id="DataTables_Table_0"
  style="display: table"
>
  <thead>
    <tr class="header_action" role="row">
      <th rowspan="1" colspan="1">
        <div class="btn-group checkall-actions">
          <label
            class="btn btn-default component-editable-checkall"
            onclick="component.editable.select_all_rows(event, this);"
          >
            &nbsp;<input type="checkbox" />&nbsp;
          </label>
        </div>
      </th>
      <th colspan="7" rowspan="1">
        <div
          class="btn-group unfocus-actions"
          style="display: inline-block"
        >
          <button
            class="btn btn-primary"
            onclick="creating_init(event, this);"
          >
            Add CSLO
          </button>

          <button
            class="btn btn-default"
            onclick="showModalSyncCSLO('MATH100 - Mathematics for General Education','237');"
          >
            CSLO Synchronization
          </button>
        </div>
      </th>
    </tr>

    <tr class="header_title" role="row">
      <th
        rowspan="2"
        style="width: 60px"
        class="sorting_disabled component-editable-multi-selector-row"
        role="columnheader"
        colspan="1"
      ></th>
      <th
        rowspan="2"
        style="width: 40em"
        class="sorting_disabled"
        role="columnheader"
        colspan="1"
      >
        CSLO
      </th>
      <th
        rowspan="2"
        class="sorting_disabled"
        role="columnheader"
        colspan="1"
      >
        Start Date
      </th>
      <th
        rowspan="2"
        class="sorting_disabled"
        role="columnheader"
        colspan="1"
      >
        End Date
      </th>
      <th colspan="2" class="slo" rowspan="1">
        SLO Performance
      </th>
    </tr>
    <tr class="header_title" role="row">
      <th
        class="slo sorting_disabled"
        role="columnheader"
        rowspan="1"
        colspan="1"
      >
        Expected
      </th>
      <th
        class="slo sorting_disabled"
        role="columnheader"
        rowspan="1"
        colspan="1"
      >
        Fall 2020
      </th>
    </tr>
  </thead>

Funny thing is that this only happens on certain screen readers like NVDA on Chrome.


Solution

  • When navigating a table the screen reader will automatically read the column and (if applicable) row header.

    As you have put the two buttons spanning across those rows they will get read out each time. This is also due to the fact you have them all set as <th> elements.

    You could move these buttons outside of the table and move the checkbox to select columns down one row (to the same row as CSLO, start date etc.).

    This will fix the issue.

    Or you could use <col> and <colgroup>

    You may also want to look into defining your columns using the <col> and <colgroup> elements. This helps screen readers correctly associate multi-row headers.

    There is a great article on how to use these from W3C with plenty of examples and here is a great article on MDN about <col> and <colspan>.

    You may still get the buttons announced though (your could put them in a <td> instead, although technically not a good practice it should stop the announcement issue and not affect usability....you would have to test in a screen reader though to be sure as I have never tried this!)

    A couple of other minor points

    There is no need for role="row" and role="columnheader" in your current table, <tr> and <th> already have those roles by default, assuming your are supporting IE8+.

    You can remove rowspan="1" and colspan="1" - cells are by default 1 row by 1 column in size so this is unneeded information (nothing to do with accessibility it will just make your markup easier to read). You only need to add rowspan and colspan when you are overriding the span.