How to create accessible tournament brackets with only HTML and CSS

As Taylor Swift has a new boyfriend and my Swiftie friends are crazy about it, I'm just curious as I watch these (boring) NFL games (yes, I'm that good of a friend) with her now-filled blank space how these tournament brackets are created and how accessible they actually are!


The title is meant to be a genuine question to the community rather than a tutorial on how to actually create accessible tournament brackets.

I've done my best to make a tournament bracket as accessible as my understanding and skills allow. I'd love it if my readers would leave their suggestions in the comments.

Table of contents

  1. What are tournament brackets?
  2. Creating a bracket: Starting point and goal
  3. Bracket using list
  4. Bracket using table
  5. Final thoughts

Following my usual approach (taking into account the meaning of the individual components and elements), I have developed a structure that I would describe as far from completely accessible, especially if the tournament has many players and the list of participants is very long.

I will explain the problems that arise for the individual examples in more detail below.

1. What are tournament brackets? <a name="chapter-1"></a>

Let's start with the basics first. What are tournament brackets and what are they used for?

Sports tournaments, such as the UEFA World Cup, NFS or NFL, work with brackets to show the progression of the tournament, with information about who is playing who, when, who is eliminated and who advances until only one player/team remains. You can think of it like a tree-shaped diagram.

SuperBowl bracket

Source: CBS|NFL

2. Creating a bracket: Starting point and goal <a name="chapter-2"></a>

Let's start with the creation of the bracket and the basis on which I want to build it and how I imagine it to be perceptible with Screen Reader.

The starting point is that the imaginary tournament for which I am creating this bracket has, say, 32 teams/individual players from different regions/countries.

There are five rounds. There will be one winner.

Tech stack

  • HTML
  • CSS

I would like to create the bracket with HTML and CSS only.

Technical environment

Device: MacBook Air, M1 2020, macOS Sonoma 14.0 Screen Reader: VoiceOver v10 Browser: Safari v17.0

Technical requirements

The tournament overview must be understandable for both sighted users and users who receive the information via a screen reader.

The table must be responsive, i.e. device-independent. Especially for sports games, people often use their cell phones to get up-to-date information about the game while watching it live.

3. Bracket using list <a name="chapter-3"></a>

First of all, I did not focus on a finished design when creating the brackets, but only spent enough time to give the reader an understanding of how the bracket should look in general.

šŸ’” CSS Note: At the time of writing this post, CSS nesting is already supported, but in Chrome and Safari only in combination with &. More information on Using CSS Nesting (MDN).

3.1. Code

Below you can see how I work with the list element. The first format contains the competing players/teams and the date summarized in one list element.

The second has each competing player/team as a link, in case the provider wants to store detailed information about them anywhere on the website, also summarized in one list element.

{% codepen %}

3.2. Output

Navigation is by right/left arrow key. Having each competing player and the date inside a span lets the screen reader announce every information in one list element at once. This is what I want to achieve as this is also the information I get when looking on it.

I use span on purpose because the behavior using a div was different as only a div at one time was announced, to connection between these elements provided.

I get the same behavior using the a elements (which of course make sense, since each of them is an individual link).

{% embed %}

ā“ But how to make it announce the whole information in one list element at once and still have them as links? Using aria-describedby? I guess this will be my next approach to try.

šŸ‘ŽšŸ¾ One downside to the list approach (and I'm more than happy for someone to tell me there's a screen reader shortcut I just didn't know about) is that the user has to go through the entire list in the first round before they can move on to the next round.

So if the list has progressed and the user only wants to keep track of the first line (e.g. what happened to that player, how far they got), they can't just use the right arrow key to go from round 1 to round 2 or 3 in the same line/bracket.

4. Bracket using table <a name="chapter-4"></a>

I also tried to create the bracket using a table.

4.1. Code

{% codepen %}

For the data within a cell, I have again subdivided the content with span. By using a div, the screen reader will again only reveal the first div in the cell and not give any indication that there is more information in the cell.

This way, the user could simply jump to the next cell without realizing that they had missed any information. But the problem still occurs when having the players/teams as a elements.

{% embed %}

4.2. Output

šŸ‘šŸ¾ One advantage of the table is that the screen reader user can now navigate back and forth between the columns using all the arrow keys without having to fight his way through the entire first column first.

{% embed %}

But the user cannot move in zigzag. As the rows in the later rounds are combined using rowspan, the user can only navigate back and forth in the first row of the combined row.

5. Final Thoughts <a name="chapter-5"></a>

  1. A grid could be used for the layout structure. It might make certain layout decisions and responsiveness easier, but I can't see it as a better approach for screen reader users. I could be wrong though.

  2. For the list version, would it make sense to add the aria-labelledby from the round heading to each outer div of a game so that it is announced every time the user moves to the next element?

  3. What if the player list is very long? Should the header be sticky so that the user still knows which round they are in when scrolling down?

  4. Maybe HTML and CSS just aren't enough to create a good user experience for keyboard or screen reader users. Would it make more sense to create a JavaScript widget where the user can navigate with arrow keys, or would that be overkill?

Thank you

Thanks for your reading and time. I really appreciate it!