Search code examples
htmlaccessibility

How can I make a dynamic collapsible menu accessible?


I have an app that is using the footable plugin to allow for responsive tables. Essentially it takes columns from a table and turns them into a collapsible menu that is dynamically injected into the table as a new row when a user clicks a button to expand and then it is removed once the user collapses it again.

If you look at this example, it sets display: none on the columns but it also appends a new tr element that has a class of .footable-detail-row and that tr houses the menu that displays the data (you'll have to shrink your browser window to see this functionality).

This plugin does not have any accessibility built in unfortunately. I have forked their repo and am trying to make it accessible. I currently have it toggling the aria-expanded attributes and the span "buttons" are now buttons in my fork.

I am stuck on how I can make this accessible because the expanded menu content is dynamically injected into the DOM and then it is removed from the DOM once the toggle button is clicked again.

Perhaps I could add an aria-label for the buttons that says something like:

When this button is clicked it will toggle a menu that is inserted into this table as a new row immediately below this one. The new row contains additional column information. To avoid this button use a screen with a width of at least 992 pixels.

Obviously that's a gigantic label but it's descriptive as to what is happening and why. Thoughts?

If I only have a button like this: <button id="myButton" aria-expanded="false">Expand Content</button> I normally would add a aria-controls="myCollapsibleMenu", however, in this instance myCollapsibleMenu doesn't exist in the DOM.

Is there any way to make a menu like this accessible short of building out my own plugin like this that adds the menu when the script loads and doesn't remove the menu from the DOM?

I have looked into the other aria attributes like aria-live but is there a way to make this work with aria-live since these menus should be associated to a specific icon? Are there any other aria attributes I can use to make this accessible? Perhaps if I use an aria-describedby on the inserted row it would let the user know how this row relates to it the row above it.

I can add any attribute to the menu I want after it is created. Would it be acceptable to aadd a descriptive aria-label of what happens when a user clicks on the button?


Solution

  • The advice in the comments is the best advice, replace the library.

    However, as with anything, there are compromises to be made and as you cannot replace the library at the moment, we can at least improve the accessibility to a level where it is "usable" with only a couple of minor tweaks.

    Please note it probably will not pass WCAG AA if that is a requirement.

    Stuff you have already done, just for clarity / to check

    The first thing is to make the part that opens and closes the additional information accessible via keyboard and improve the semantics.

    If you are able I would replace the contents of that column with <button> elements instead of just text with a click handler.

    That gives you all of the relevant keyboard functionality you need.

    Obviously that would mean finding and adjusting the click handler responsible for expanding the row and replacing it, but hopefully it would be as simple as changing the CSS selector.

    button action

    The second thing you need to do is indicate to screen reader users the action of the button.

    This can easily be achieved with either an aria-label or use some visually hidden text (my preference due to compatibility)

    This simply needs to explain that it reveals more information.

    Something like "{name} (reveal all information in row below)".

    a bit of tidy up with the icon and the button ARIA

    Finally, let's hide that plus symbol from screen readers just to ensure it doesn't get announced using aria-hidden="true"

    Oh and add aria-expanded="false" to the buttons and toggle that when the row below is added.

    Quick example of desired output

    An example of the desired HTML output (based on your fiddle) is below:

    <td style="display: table-cell;" class="footable-first-visible">
    <button aria-expanded="false">
       <span class="footable-toggle fooicon fooicon-plus" aria-hidden="true"></span>
       Annemarie
       <span class="visually-hidden">(reveal all information in row below)</span>
    </td>
    </button>
    

    Things you have not done yet that are still worth doing

    You mentioned aria-controls, I would say use aria-owns instead (just a judgement call based on the slight differences, in reality it will not make much difference to user-experience).

    Now as you have indicated you have an issue where the item that you want to point to with aria-owns is not in the DOM.

    As such you can add this dynamically as a "best we can do" scenario.

    So the second the new row is added to the table, add an ID to that row and then add aria-owns="your-id" to the controlling <button>.

    The beauty is that if the row is expanded and the button gets refocused (or a screen reader user asks for the current element to be read out again) it will announce the relationship.

    When the row is collapsed again, remove the aria-owns attribute.

    example with aria-owns and aria-expanded="true"

    Notice how I also changed the visually-hidden text to "close all information..." as the button purpose has changed.

    <td style="display: table-cell;" class="footable-first-visible">
    <button aria-expanded="true" aria-owns="your-new-id">
       <span class="footable-toggle fooicon fooicon-plus" aria-hidden="true"></span>
       Annemarie
       <span class="visually-hidden">(close all information in row below)</span>
    </td>
    </button>
    

    One last thing that would improve accessibility

    Now that you have made it usable via keyboard and provided hints as to relationships there is one more thing you can do to improve the accessibility for screen reader users.

    Add instructions!

    I often encounter scenarios where a fix would take a long time but the only big issue with accessibility is actually discoverability (i.e. once you know how a widget is constructed and how to navigate it, it doesn't matter as much that it isn't perfectly formed.)

    So have a button before the table called "help".

    This can then explain the behaviour of the table ("click on a person's name in the first column to expand additional information in a new row below. Within that row a small table with additional fields will be added").

    This simple step can really help screen reader users as they can go "ok so there is a button, if I press it there is a new row added, within that row there is a nested table" and know where to look for information.

    Conclusion

    Couple the instructions with the steps earlier and I am confident that although the table is not "accessible" it would be entirely usable and a reasonable experience for screen reader users and keyboard only users alike.

    Obviously (for anyone else landing on this question) this is not the ideal solution, the point here is to do the best we can for now and plan to replace the current solution at the next iteration.