How to make a table row a link

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.

The problem

Using native HTML table elements, it not valid HTML to wrap an anchor (<a>) element around a table row (<tr>) element.

Solutions

Solution 1: Use JavaScript

JavaScript can be used to programmatically navigate a user to another page when a table row is clicked. There are many ways to do this with JavaScript, but one way is to add an event listener on every table row element and use 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 window.open([url], '_blank').

This is the same javascript solution as above, except it handles control/command clicking a row to open it in a new table.

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.

Link preview in the bottom left of the browser window when hovering over an anchor element.

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 <a> elements:

Inspecting the cell with the nested link, you can see that the anchor elements go from being nested to being siblings.

html
1<a href="#" tabindex="-1" class="row-link"></a>
2<a href="#link">Link</a>

Chris Coyier has a great article going in-depth on nested links and some attempts at getting around them. I should point out that if you're using React and you try to nest links, they will end up showing up in the rendered HTML markup as nested. This is because React uses JavaScript to create the HTML markup, so this kind of thing is possible. However, just because this can be done in React, doesn't mean it's valid HTML. It's probably a good idea to avoid using invalid HTML since other tools, such as screen readers or search engine crawlers, likely expect the HTML to use valid syntax.

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.

Real-world examples

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

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.

GitHub pull request table

Reddit

Reddit uses <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.

Reddit list view

From a user experience point of view, it can be very convenient to be able to click anywhere on a table row in order to navigate to another page. For that reason, I think it is an acceptable pattern. However, I would not use an anchor element, but rather use JavaScript (as suggested in option #2) to handle the click event on a table row and try to have an anchor element within the row pointing to the linked page for users to be able to hover over it and get a preview of the page's URL. I would also prevent entire table rows to be focusable and instead rely on the links within the table row for keyboard navigation.

Resources

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 <a> elements

Flexible data tables with CSS Grid: Explains how to style data tables with CSS Grid



Robert Cooper's big ol' head

Hey, I'm Robert Cooper and I write articles related to web development. If you find these articles interesting, follow me on Twitter to get more bite-sized content related to web development.