Search code examples
html-tableaccessibilityscreen-readersfootnotes

How to handle footnotes in a table in regards to screen readers and accessibility?


I'm working on some simple tables and trying to make them accessible. The tables have footnotes throughout, some are in captions, some are in the table body/data. The footnotes themselves are in a tfoot which I am hiding with aria-hidden.

The caption below is probably the easiest thing to take a look at what I've done because it's right at the top.

I'm basically hiding the footnote numbers and using screen reader only text to read out the footnote text right after whatever is referencing that footnote. I also prefix and suffix the footnote text with "footnote X begin" and "footnote X end" to provide more context so it's hopefully clear that a footnote is being read and where it starts and stops.

There won't be a ton of footnotes in the tables. The footnotes I have provided are the longest examples as well.

From my testing in NVDA, this seems to work pretty well. Is there a better way to handle table footnotes for screen readers than the pattern I have?

I only have NVDA and Narrator to test with.

Here is the html:

<table>
    <caption>
        <h4>
            Skilled nursing facility care
            <sup aria-hidden="true">1</sup>
            <span class="sr-only">
                <em>footnote 1 begin</em>
                A benefit period begins on the first day you receive services as an inpatient in a hospital and ends after you have
                been out of the hospital and have not received skilled care in any other facility for 60 days in a row.
                <em>footnote 1 end</em>
            </span>
        </h4>
        <p>
            You must meet Medicare’s requirements including three inpatient hospital days, prior to entering a Medicare-approved skilled nursing facility within 30 days
        </p>
    </caption>
    <thead>
        <tr>
            <th scope="col" class="cell-no-bkg"></th>
            <th scope="col">Medicare pays</th>
            <th scope="col">Plan pays</th>
            <th scope="col">You pay</th>
        </tr>
    </thead>
    <tfoot>
        <tr>
            <td colspan="4">
                <ol aria-hidden="true">
                    <li>
                        A benefit period begins on the first day you receive services as an inpatient in a hospital and ends after you have
                        been out of the hospital and have not received skilled care in any other facility for 60 days in a row.
                    </li>
                    <li>
                        Notice: When your Medicare Part A hospital benefits are exhausted, the insurer stands in place of Medicare and will
                        pay whatever amount Medicare would have paid up to an additional 365 days as provided in the policy’s “core benefits.”
                        During this time, the hospital is prohibited from billing you for the balance based on any difference between its billed
                        charges and the amount Medicare would have paid.
                    </li>
                </ol>
            </td>
        </tr>
    </tfoot>
    <tbody>
        <tr>
            <th scope="row" class="th-in-body">
                <p>First 20 days</p>
            </th>
            <td>
                <p>All approved amounts</p>
            </td>
            <td>
                <p>$0</p>
            </td>
            <td>
                <p>
                    $0
                    <sup aria-hidden="true">1</sup>
                    <span class="sr-only">
                        <em>footnote 1 begin</em>
                        A benefit period begins on the first day you receive services as an inpatient in a hospital and ends after you have
                        been out of the hospital and have not received skilled care in any other facility for 60 days in a row.
                        <em>footnote 1 end</em>
                    </span>
                </p>
            </td>
        </tr>
        <tr>
            <th scope="row" class="th-in-body">
                <p>21st through 100th day</p>
            </th>
            <td>
                <p>All but $200 per day</p>
            </td>
            <td>
                <p>$0</p>
            </td>
            <td>
                <p>
                    Up to $200
                    <sup aria-hidden="true">2</sup>
                    <span class="sr-only">
                        <em>footnote 2 begin</em>
                        Notice: When your Medicare Part A hospital benefits are exhausted, the insurer stands in place of Medicare and will
                        pay whatever amount Medicare would have paid up to an additional 365 days as provided in the policy’s “core benefits.”
                        During this time, the hospital is prohibited from billing you for the balance based on any difference between its billed
                        charges and the amount Medicare would have paid.
                        <em>footnote 2 end</em>
                    </span>
                </p>
            </td>
        </tr>
        <tr>
            <th scope="row" class="th-in-body">
                <p>101st day and after</p>
            </th>
            <td>
                <p>$0</p>
            </td>
            <td>
                <p>$0</p>
            </td>
            <td>
                <p>All costs</p>
            </td>
        </tr>
    </tbody>
</table>

Solution

  • It may not be a good idea to completely hide the footnote logic and put them inline for screen reader users.

    As I can see at a first glance, some of these footnotes are repeated several times and aren't that short. As a screen reader user, I certainly don't want to have them repeated several times. Once I got the explanation at first occurence, that's enough.

    You logic is complex, but valid and interesting when the notes aren't repeated / referenced several times, and when the notes are rather short. For longer notes and/or when they are referenced several times as in your example, I rather recommend to keep a traditional, much simpler logic such as the following:

    Referencing the footnote:

    <sup><a href="#note1" id="backref1"><span class="sr_only">Footnote&nbsp;</span>1</a></sup>
    

    And the footnote itself:

    <p id="note1">content of the footnote 1 bla bla bla
    <a href="#backref1">Go back</a></p>
    

    Note that, in the footnote, there's a link to go back to the first place where the note was referenced.

    Side unrelated note: be careful to don't put too long text in your <h4>. It's an heading, not suited to contain an entire paragraph of text.

    Side unrelated note 2: the <caption> element is also threated like an heading for the table. As such, it's content is also supposed to be rather short. It isn't suited to contain entire paragraphs of text either.