DEV Community

Cover image for Make table rows clickable as links with tanstack-table and CSS
Elisabeth Leonhardt
Elisabeth Leonhardt

Posted on

Make table rows clickable as links with tanstack-table and CSS

You want your entire table row to be a real clickable link? Here, I present you with a practical and accesible solution.

gif of the result

Link to the codesandbox: Check it out!

Step 1: Create your table

Use whatever technologies you like for this: I went with React and tanstack-table, because that’s what I currently use at work.



type Items = {
  ranking: number;
  url: string;
  name: string;
};

const data: Items[] = [
  {
    ranking: 1,
    url: "https://google.com",
    name: "Google",
  },
  {
    ranking: 2,
    url: "https://bing.com",
    name: "Bing",
  },
  {
    ranking: 3,
    url: "https://yahoo.com",
    name: "Yahoo",
  },
];
const columnHelper = createColumnHelper<Items>();
const columns = [
  columnHelper.accessor("ranking", {
    cell: (info) => info.getValue(),
  }),
  columnHelper.accessor("name", {
    cell: (info) => info.getValue(),
  }),
  columnHelper.accessor("url", {
    cell: (info) => info.getValue(),
  }),
];
export function Table() {
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
  });
  return (
    <div>
      <table>
        <thead>
          {table.getHeaderGroups().map((headerGroup) => (
            <tr key={headerGroup.id}>
              {headerGroup.headers.map((header) => (
                <th key={header.id} className="table-head">
                  {header.isPlaceholder
                    ? null
                    : flexRender(
                        header.column.columnDef.header,
                        header.getContext(),
                      )}
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody>
          {table.getRowModel().rows.map((row) => (
            <tr key={row.id} className="data-rows">
              {row.getVisibleCells().map((cell) => (
                <td key={cell.id} className="table-cell">
                  {flexRender(cell.column.columnDef.cell, cell.getContext())}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}


Enter fullscreen mode Exit fullscreen mode

Step 2: Add an additional column to your table

I added it on the left side, but that’s indifferent. Here, it’s filled with yellow, so you can see it.

Table with one additional column

Step 3: Put your link inside the empty column

In the small column, put the link that every row should lead to inside an anchor tag.



...
    <thead>
          {table.getHeaderGroups().map((headerGroup) => (
            <tr key={headerGroup.id}>
              {/*⬇️ add an extra column here */}
              <th key="extra-column" aria-label="Search Engine Links"></th>
              {headerGroup.headers.map((header) => (
                <th key={header.id} className="table-head">
...
        <tbody>
          {table.getRowModel().rows.map((row) => (
            <tr key={row.id} className="data-rows">
              {/*⬇️ add a cell with an empty link for every row
              below the empty column header */}
              <td>
                <a
                  href={row.original.url}
                  aria-label={row.original.url}
                  className="row-link"
                ></a>
              </td>
              {row.getVisibleCells().map((cell) => (
...


Enter fullscreen mode Exit fullscreen mode

Step 4: Position the link so it spans over the whole row

Now, that the link is part of the table, let’s make it overlap over the whole row with CSS:



tr {
  border: 1px solid white;
  position: relative;
  height: 3rem;
}

.row-link {
  position: absolute;
  top: 0;
  left: 0;
  content: "";
  width: 100%;
  height: 3rem;
}

.data-rows:hover {
  background-color: #a8a5a5;
}



Enter fullscreen mode Exit fullscreen mode

Whole clickable rows in yellow

I added a yellow background and borders to every element, so it’s easier to see. With the absolute positioning in relation to the table row, the anchor tag spans over the whole row and makes it clickable.

Red outline for better accessibility

By adding an adequate outline to the anchor tag, the focus is also including the whole row and making it therefore great to tab through. 🥳

⚠️Notes about Accessibility⚠️

  • 🧑🏽‍🦯 The empty column header and the empty anchor tags can be confusing for people using screen readers, this is why I added an aria-attribute to them.
  • ⤵️ I customized the outline for focus-visible, so the links are clearly marked as something clickable and accessible over the keyboard.
  • 🎨 Mine is of course an example to show the concept - always check for sufficient contrast when choosing your colors.

I love this solution - it's so elegant! Hope this helped you!

Top comments (2)

Collapse
 
vago profile image
Varun • Edited

Nice, thanks for a nice and simple way. I guess, another way could have been to add the link column as the first column in columns list and let cell field return the link tag? What do you think about that? I am new to tanstack table and wondering when it's good to define all columns in the columns array vs adding columns in the render JSX.

Collapse
 
balthazur profile image
Balthasar Huber

position: relative isn't supposed to work on tr elements, and e.g. does not work in Safari.