Allowing a table row to be a link is not as simple as one might think. This article explains what the main issue is with making links out of table rows, provides some solutions to the problem, showcase some real-world examples, and question whether having a table row as a link is something that should even be done.
Using native HTML table elements, it not valid HTML to wrap an anchor (
<a>) element around a table row (
window.location.href to navigate the user to another page.
A link has been added in the cells of the last column to demonstrate that this solution works fine when some of the table rows contain links (which cannot be said for some of the other solutions to be proposed).
Note that with this solution, users will not be able to control/command click on a row to open the linked page in a new tab (as is normal behavior when using
<a> elements). However, you could add an event listener to detect if the control/command key is pressed and open the page in a new tab if the row is clicked while the control/command key is pressed. Opening a page in a new window can be done programmatically using
The only remaining issue with this solution is that the user doesn't get the URL preview provided by browsers when hovering over anchor elements. There is currently no workaround for this.
Solution 2: Use anchor elements in every table cell
Anchor elements can be used to link a row if they are used in every cell. To prevent every table cell to be focusable (which would be annoying when tabbing through the table with a keyboard), only allow the first cell to be focusable by adding a
tabindex="-1" to all anchor elements except for the one in the first column. Using the
:focus-within pseudo selector, it's possible to apply styles to the entire row when the first cell is focused, giving the impression that the entire row is focused while tabbing through the table.
One issue with this solution is that it's not valid HTML to nest anchor elements within one another. That means that it would not be possible to add another
<a> element inside the table row. When nesting
<a> elements in an HTML file, they will appear as siblings when rendered in a browser. Here's what happens in the table when trying to nest
Inspecting the cell with the nested link, you can see that the anchor elements go from being nested to being siblings.
1<a href="#" tabindex="-1" class="row-link"></a>2<a href="#link">Link</a>
One workaround that can be done is to not wrap the content inside of a table cell with an
<a> element, but instead, add an empty
<a> in each cell and then absolutely position it relative to the cell so that it covers the entire cell area. This way, it's possible to have other links within the table cells.
Note that the
<a> links that are not absolutely positioned should have the
position: relative and
z-index: 1 CSS styles applied to allow them to sit above the absolutely positioned
<a> element in the stacking context (which allows them to be clickable).
Solution 3: Use CSS grid to create a table
Using CSS grid, you can build out your table with
<div> elements instead of native HTML table elements, and then you can use
<a> elements for the table rows. David Lynch explains just how well you can build out tables using CSS grid.
Note that similar to the previous solution, if the entire row is an
<a> element, then it is not possible to have nested
<a> elements. However, we can instead add the
<a> element inside the table row and absolutely position it to cover the entire table row.
Let's take a look at two real-world examples of linking rows: GitHub and Reddit.
Although the following examples might be better classified as "lists" rather than "tables", the same logic/observations apply to tables.
GitHub doesn't make the entire row in their pull request list/table clickable. You need to click on the title of the pull request in each row to navigate to that page. This makes things straight-forward from an implementation and accessibility point of view.
<div> elements for their lists so you don't get an indication to what URL you will be navigated to while hovering over the row. However, as a compromise, you can hover over the title in the row and it uses a proper
<a> element that will indicate the URL when hovering over it. Also, when tabbing focusable elements in the list, the entire rows themselves aren't focusable, but rather each actionable item in the row is focusable.
Should table rows be links in the first place?
Stack Overflow discussion on making an entire row clickable
React Table: React hooks to help you build tables
Inclusive components - Data tables: building tables with accessibility in mind
Nested Links: article by Cris Coyier explaining how to deal with nested
Flexible data tables with CSS Grid: Explains how to style data tables with CSS Grid