573

I'm using Bootstrap and the following doesn't work:

<tbody>
    <a href="#">
        <tr>
            <td>Blah Blah</td>
            <td>1234567</td>
            <td>£158,000</td>
        </tr>
    </a>
</tbody>
ryyker
  • 22,849
  • 3
  • 43
  • 87
user1038814
  • 9,337
  • 18
  • 65
  • 86

28 Answers28

636

Author's note I:

Please look at other answers below, especially ones that do not use jquery.

Author's note II:

Preserved for posterity but surely the wrong approach in 2020. (Was non idiomatic even back in 2017)

Original Answer

You are using Bootstrap which means you are using jQuery :^), so one way to do it is:

<tbody>
    <tr class='clickable-row' data-href='url://'>
        <td>Blah Blah</td> <td>1234567</td> <td>£158,000</td>
    </tr>
</tbody>


jQuery(document).ready(function($) {
    $(".clickable-row").click(function() {
        window.location = $(this).data("href");
    });
});

Of course you don't have to use href or switch locations, you can do whatever you like in the click handler function. Read up on jQuery and how to write handlers;

Advantage of using a class over id is that you can apply the solution to multiple rows:

<tbody>
    <tr class='clickable-row' data-href='url://link-for-first-row/'>
        <td>Blah Blah</td> <td>1234567</td> <td>£158,000</td>
    </tr>
    <tr class='clickable-row' data-href='url://some-other-link/'>
        <td>More money</td> <td>1234567</td> <td>£800,000</td>
    </tr>
</tbody>

and your code base doesn't change. The same handler would take care of all the rows.

Another option

You can use Bootstrap jQuery callbacks like this (in a document.ready callback):

$("#container").on('click-row.bs.table', function (e, row, $element) {
    window.location = $element.data('href');
});

This has the advantage of not being reset upon table sorting (which happens with the other option).


Note

Since this was posted window.document.location is obsolete (or deprecated at the very least) use window.location instead.

Community
  • 1
  • 1
Ahmed Masud
  • 21,655
  • 3
  • 33
  • 58
  • 118
    You may want to also change the cursor with the css: tr.clickableRow { cursor: pointer; } – Winston Kotzan Oct 30 '13 at 18:08
  • 83
    Just wanted to add that you shouldn't use `href` attribute on a `tr`, since it's not a valid attribute for this element. Use data attributes instead: `data-url="{linkurl}"` and in js code: `$(this).data('url')` – Maksim Vi. Jan 17 '14 at 19:57
  • 12
    You can avoid using a class on each row, and decorate the table with a class name of `clickable_row` (CamelCase is against HTML standards and should be lower case (I had issues with cross browser a few times with this)) and then the jQuery is `$('.clickable_row tr').click(function ...` But really you should be using `data-` to hold data, instead of `href` since that is the specification for custom data. `data-url` and jquery will access it like `$(this).data(url);` – Piotr Kula Apr 14 '14 at 19:58
  • 2
    [Here is a solution that only needs HTML and CSS.](http://stackoverflow.com/a/23120665/2463800) Hope this helps. – Trevin Avery Apr 16 '14 at 21:42
  • 3
    FYI: If you can, you should leave a link somewhere in the tr for people who have Javascript disabled. – hitautodestruct May 07 '14 at 15:23
  • 1
    What is the correct way of handling this situation? The correct way to do it using only HTML and CSS, it would be to insert an A tag inside each cell, and put it to width:100% and height:100% with display:block (or inline-block). But, having an A in each cell is an ideia that I don't approve that much aswell. As neither doing this by Javascript. It sounds too tricky. – Ivo Pereira Oct 02 '14 at 14:05
  • 2
    @IvoPereira avoiding javascript just for the sake of avoiding javascript in today's world is weird. Anyone who chooses to turn off javascript for sake of "security" is also making a choice to lose functionality. There is no need to cater to them. – Ahmed Masud Nov 13 '14 at 12:06
  • 60
    Not a big fan of this solution because users don't see the link URL at the bottom of the browser when hovering, and more importantly can't wheel-click on the link to open it in a new tab. Inserting an `a` tag with `display: block;` inside each cell is a bit annoying but it seems like the most usable way to solve this issue. – Maxime Rossini Dec 04 '14 at 10:18
  • @madmox both of your points were out of scope for OP's question. I would assume that in a practical application, the interface designer would take other steps. For instance, it's easy enough to update window.status with onhover events, and middle click or right click can also be trapped. Having said that, I personnally would NOT use a tables the way OP is using them, I'd put my data in divs. I did give this answer, however, because I like to keep my answer's band very narrow—always assuming that there may be other restrictions that the OP hasn't pointed out. – Ahmed Masud Dec 04 '14 at 14:19
  • 2
    You can't change `window.status` with the default configuration of any modern browser. Also, in my opinion, "clickable as a link" means not only "left click-clickable". It's also quite disapointing having to trap all the events already implemented for hyperlink tags. It looks promising on the paper (beacause: clean html), but in the end I see too many drawbacks to not consider using `` tags inside each table cell or, like you suggested, not using table at all (which is also quite frustrating for actual tabular data). – Maxime Rossini Dec 04 '14 at 19:14
  • @madmox as a principle i agree – Ahmed Masud Dec 04 '14 at 22:22
  • How about `$('.table > tbody > tr').click(function() {...do stuff...});` doesn't even need a class if you want to make rows (in all tables on page) clickable. This saves a lot of work in adding new class to rows. – Fr0zenFyr Nov 28 '15 at 06:10
  • 1
    You may also consider using delegation `on('click', function(){...})` to register the click event handler with dynamically created elements (e.g. a table that was returned via an ajax call) – ira Jul 26 '16 at 07:29
  • `window.document.location = ...` didn't work for me when page had a `form` tag on the page (eg. another select box which uses javascript). So I would go for @MaximeRossini solution of using `a` with `display:block;` – Dimitry K Jul 28 '16 at 17:15
  • It is now window.location the API has changed since this answer was posted – Ahmed Masud Jul 28 '16 at 21:15
  • 1
    It is easy to do a "hack" with JS. I excpected a HTML solution. And, this is not good for SEO. – Mehdi Feb 20 '17 at 01:04
  • @WinstonKotzan The best way to do that in bootstrap is to add role="button" to the element. This applies the cursor with no additional css needed. – Todd Skelton Apr 12 '17 at 19:09
  • @ToddSkelton $role="button"$ is an aria specification, and can be used but different browsers will give different results. – Ahmed Masud Apr 12 '17 at 23:02
  • 1
    `$("[data-href]").click` even better, no need for classes – spedy Apr 21 '17 at 06:46
  • yes but you're not guaranteed that someone else is not using `data-href` attribute for something else in the underlying libraries or templates. – Ahmed Masud Apr 21 '17 at 12:39
  • 2
    Do not forget to add attribute `tabindex="0"` on `tr` to make the row focusable. It's important for accessibility. – Steven Mouret Jun 20 '17 at 15:37
  • Is bootstrap-table official part of bootstrap? – Anwar Oct 09 '17 at 10:13
  • I am getting "Cannot GET /undefined" error when using node.js. Once I click the table row, my tab changes to displaying just the error line of text. The link in "data-href" (or "data-url") works separately. Any advice? – Shane Sepac Mar 10 '19 at 06:13
  • 1
    For me, part of the ordeal is to have my code output a-elements for all cells. But if we let the client handle that, I'd be fine with that. So have the client wrap all cell contents in a-elements for tr [data-href] etc. – Herbert Van-Vliet Apr 22 '19 at 19:00
  • This won't work with react, I suggest adding a `` tag within each TD! – Dimitri Kopriwa Dec 23 '20 at 16:31
  • 2
    Author's notes are useful for sure, but it would be better to simply put a modern approach there instead (and keep the old answer below it for posterity) – stevec Jan 03 '21 at 06:26
  • It's frustrating that this was edited to assert "surely the wrong aproach in 2020" but then did not provide any feedback about what would be better than this. Even if all the editor meant is "use React or another framework instead," they should have clarified. Among the 'alternatives' listed, it's not clear which do or do not apply to "being better / more correct in 2020." The warning, in short, feels really incomplete and needs more context. – m.arthur Nov 30 '22 at 22:54
312

You can't do that. It is invalid HTML. You can't put a <a> in between a <tbody> and a <tr>. Try this instead:

<tr onclick="window.location='#';">
   ...
</tr>

add style for pointer view

[data-href] { cursor: pointer; }

When you work up to it, you'd want to use JavaScript to assign the click handler outside the HTML.

Davy de Vries
  • 4,578
  • 2
  • 14
  • 29
davidfurber
  • 5,274
  • 1
  • 20
  • 11
  • 6
    @Aquillo the OP specifically states that s/he's using bootstrap. so a jQuery solution would be better within the framework – Ahmed Masud Jun 17 '13 at 13:07
  • 54
    @AhmedMasud In this case, yes. Though for any future readers plain JS might be a better solution. Since that's the purpose of Stackoverflow, I still consider my comment to be a valid one. – Menno Jun 17 '13 at 14:14
  • 3
    The separation of behavior and markup is certainly to be preferred. If anything, I would say that href is not a valid attribute on a tr. It should be replaced with a data-href, and replace $(this).attr with $(this).data. – davidfurber Jun 18 '13 at 03:15
  • 2
    Or you could make the ".clickableRow" class event binding approach look for the first `` inside the clicked row. (that would also degrade gracefully) – Jason Sperske Jan 16 '14 at 07:46
  • You are right about using `href` on `tr` is not valid with HTML specifications. But if you use a library that can extend functionality, its perfectly valid to use custom (unreserved keywords) on DOM, since the framework support this. With jquery you can simply do `$(.class mycustomtag').click(function() ...` - where onclick is HTML5 specific and can cause issues with older browsers – Piotr Kula Apr 14 '14 at 19:55
  • also works perfect for in-page (anchor) navigation from table rows. – mcy Sep 09 '14 at 12:40
  • 3
    If you're using ES6 syntax, you can execute the link click like so: `onClick={() => window.open('https://stackoverflow.com/', '_blank')}` – Louie Bertoncin Jul 09 '17 at 15:52
  • 1
    Unfortunately, this solution breaks "middle click to open link in new tab". The onclick will only work for a left click, and I'm unaware of any way to change it to get middle clicks opening in a new tab. – Jez Nov 22 '20 at 17:47
  • Be aware this option will probably not work if you use Content Security Policy (CSP). When adopting strict CSP, inline scripts will be blocked. For more information see [https://content-security-policy.com/](https://content-security-policy.com/) – Tom Schmitz Dec 09 '22 at 13:46
260

You could include an anchor inside every <td>, like so:

<tr>
  <td><a href="#">Blah Blah</a></td>
  <td><a href="#">1234567</a></td>
  <td><a href="#">more text</a></td>
</tr>

You could then use display:block; on the anchors to make the full row clickable.

tr:hover { 
   background: red; 
}
td a { 
   display: block; 
   border: 1px solid black;
   padding: 16px; 
}

Example jsFiddle here.

This is probably about as optimum as you're going to get it unless you resort to JavaScript.

Community
  • 1
  • 1
dsgriffin
  • 66,495
  • 17
  • 137
  • 137
  • 21
    This is the best solution, no jquery no javascript only CSS, i.e. my link could be different not href, with multiple parameters like so I keep it and change only the style. Many thanks. – TiyebM Feb 14 '15 at 11:33
  • ...@Bono, If you try to do something other than just open a href this solution won't fit for your needs – Li3ro Aug 03 '15 at 07:42
  • 4
    @daniel good answer but If the cell extends down, doesn't work properly like this http://jsfiddle.net/RFFy9/253/ – midstack Aug 27 '15 at 12:07
  • 5
    Great! This solution enables open the link in a new tab if the user wants. But empty columns will not have links. – Ignacio Pérez Jan 23 '16 at 16:19
  • 1
    The downside of this solution is it's not ideal for accessibility; you have multiple links next to each other going to the same place. – Anna Rouben Jan 29 '16 at 19:35
  • 12
    @AnnaRouben I'm going to have to disagree: having multiple similar links is a very small downside compared to the upsides (works without JS, screen reader can read where the link is leading to, can ctrl-click to open in new tab...) Pure-HTML solutions work almost always better in assistive software than JS solutions. – JJJ Feb 01 '16 at 13:00
  • 1
    I am using Flask micro framework and Jinja to build my application in python and this is the only valid solution that helps me solve my problem! – Clever Programmer May 21 '16 at 08:40
  • @IgnacioPérez - for an empty column, you could maybe put an   inside the cell ... bit hacky, but ... – Algy Taylor Sep 27 '16 at 07:38
  • The person asked for all TR not TD. – Mehdi Feb 20 '17 at 00:58
  • 1
    @midstack you can fix that by putting the border on the `td`: `td { border: 1px solid black; }` – Wayne Bloss Dec 01 '17 at 02:36
  • 10
    I like this solution because of how accessible it is. Users can tab through the links, plus you can open links in new tabs. What I've done in my app is put `tabindex="-1"` on all but the first `` link, so the user tabs row to row, not cell to cell. Plus, you can still highlight/outline the entire row if you want using the `:focus-within` CSS pseudo-class. – Jonathan Jan 23 '19 at 13:55
  • 2
    I'm going to go ahead and use this solution. I hate the javascript solutions because they make these links not function as normal links in the browser. It's shocking to me how popular javascript solutions are for this. – GrumpyCrouton Jun 03 '19 at 13:59
  • @WayneBloss that doesn't make it clickable though, just puts the border around the td. If you click the parts outside the padded link then nothing happens. – gbjbaanb Jul 18 '19 at 13:41
108

A linked table row is possible, but not with the standard <table> elements. You can do it using the display: table style properties. Here and here are some fiddles to demonstrate.

This code should do the trick:

.table {
  display: table;
}

.row {
  display: table-row;
}

.cell {
  display: table-cell;
  padding: 10px;
}

.row:hover {
  background-color: #cccccc;
}

.cell:hover {
  background-color: #e5e5e5;
}
<link href="https://stackpath.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" type="text/css" />

<div role="grid" class="table">
  <div role="row" class="row">
    <div role="gridcell" class="cell">
      1.1
    </div>
    <div role="gridcell" class="cell">
      1.2
    </div>
    <div role="gridcell" class="cell">
      1.3
    </div>
  </div>

  <a role="row" class="row" href="#">
    <div role="gridcell" class="cell">
      2.1
    </div>
    <div role="gridcell" class="cell">
      2.2
    </div>
    <div role="gridcell" class="cell">
      2.3
    </div>
  </a>
</div>

Note that ARIA roles are needed to ensure proper accessibility since the standard <table> elements are not used. You may need to add additional roles like role="columnheader" if applicable. Find out more at the guide here.

mfluehr
  • 2,832
  • 2
  • 23
  • 31
Trevin Avery
  • 2,751
  • 2
  • 20
  • 31
  • 18
    Now try to apply dataTables plugin to this one! :) – Afonso Gomes Nov 05 '14 at 15:22
  • 10
    This is the correct answer IMHO, because it retains all user agent tools related to links: search (eg. `/` key in Firefox), navigation (`tab` key), Copy link location, Open in new tab/window, etc. even for accessible / special needs browsers. My only nitpick is that I wouldn't nest a ` – Tobia Jul 05 '16 at 13:42
  • Applying third-party plugins and libraries to such CSS tables might involve a bit more work, but it's usually copy-paste and replace. For example, I just duplicated Bootstrap's own `_tables.scss` and a few other random pieces, replacing all occurrences of table elements with the CSS classes I chose to use (which are simply the same as the elements: `th` → `.th`) Not much work compared to the benefits, really. – Tobia Jul 05 '16 at 13:47
  • 3
    Nice answer, but this is only a solution if the table was just used for proper aligning (which is the case in many situations!). For tabular data, the semantic `` is there for a reason. But this still beats any javascript solution :)
    – Marten Koetsier Jun 22 '17 at 14:03
  • 1
    Although this is a very clever work-around, it is just that. It is not actually a table and so, as the author mentions, will present problems to accessibility. It will very likely cause issues with other things that are expecting a table but are getting one. – Tyson Gibby Feb 19 '20 at 20:41
  • W3C Nu Html Checker claims it's an error to have an `` tag with both `role=row` and a `href` – user8977154 Aug 07 '23 at 19:37
73

Achieved using standard Bootstrap 4.3+ as follows - no jQuery nor any extra css classes needed!

The key is to use stretched-link on the text within the cell and defining <tr> as a containing block.

<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>

<table class="table table-hover">
  <tbody>
    <tr style="transform: rotate(0);">
    <th scope="row"><a href="#" class="stretched-link">1</a></th>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <th scope="row">2</th>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
    <tr>
      <th scope="row">3</th>
      <td>Larry</td>
      <td>the Bird</td>
      <td>@twitter</td>
    </tr>
  </tbody>
</table>

You can define containing block in different ways for example setting transform to not none value (as in example above).

For more information read here's the Bootstrap documentation for stretched-link.

Břetislav Hájek
  • 3,056
  • 2
  • 15
  • 17
Krishna Gupta
  • 2,025
  • 19
  • 20
  • 4
    This answer deserves more vote. No javascript at all. And what is that `scope="row"` for? I don't use scope and the row still behaves as a link. – Christhofer Natalius Dec 20 '19 at 03:19
  • @ChristhoferNatalius thanks! My original answer didn't contain the `scope="row"` - please check out the history if you'd like to see what else may have been edited. I didn't revert the edits, though, as the code snippet seems to work (as did the original) and I didn't get the chance to test the new code exhaustively :-) – Krishna Gupta Dec 23 '19 at 13:57
  • 4
    The downside of this is because the link will be on top of the columns, you can't copy the text, and attribute title in td is not showing if hovered by mouse. So unfortunately, I have to go back to old way, put the link only to one column. – Christhofer Natalius Feb 07 '20 at 04:32
  • 9
    I liked this solution, but sadly, it is not cross-browser (Chrome/Firefox are OK but not Safari). The problem is due to `tr` tag that is not recognized as the rules for the containing block among browsers... https://stackoverflow.com/questions/61342248/streteched-link-bootstrap-utilities-doesnt-work-in-chrome – pom421 Apr 23 '20 at 10:08
  • 2
    Yes, this does seem to **break** table links in Safari – the hover behavior goes completely haywire. [This comment on #28608](https://github.com/twbs/bootstrap/issues/28608#issuecomment-479862777) seems to indicate that it's not possible to get the desired behavior on tables with `stretched-link`. – Jo Liss Jun 15 '20 at 18:34
  • This fix won't work with my table in Django. All the rows have the same (last) link. So this is useless for me. But i like the answer for other projects! – Zegert Jan 27 '21 at 10:28
  • 1
    This doesn't seem to be working (Firefox 78.7.0, Chrome 89.0.4389.114), all rows would point to the same href from the last row – wi2ard Apr 14 '21 at 10:55
28

A much more flexible solution is to target anything with the data-href attribute. This was you can reuse the code easily in different places.

<tbody>
    <tr data-href="https://google.com">
        <td>Col 1</td>
        <td>Col 2</td>
    </tr>
</tbody>

Then in your jQuery just target any element with that attribute:

jQuery(document).ready(function($) {
    $('*[data-href]').on('click', function() {
        window.location = $(this).data("href");
    });
});

And don't forget to style your css:

[data-href] {
    cursor: pointer;
}

Now you can add the data-href attribute to any element and it will work. When I write snippets like this I like them to be flexible. Feel free to add a vanilla js solution to this if you have one.

AbdelElrafa
  • 881
  • 8
  • 16
15

Here is simple solution..

<tr style='cursor: pointer; cursor: hand;' onclick="window.location='google.com';"></tr>
Murad
  • 1,064
  • 16
  • 13
14

One solution that was not mentioned earlier is to use a single link in a cell and some CSS to extend this link over the cells:

table {
  border: 1px solid;
  width: 400px;
  overflow: hidden;
}

tr:hover {
  background: gray;
}

tr td {
  border: 1px solid;
}

tr td:first-child {
  position:relative;
}

a:before {
  content: '';
  position:absolute;
  left: 0;
  top: 0;
  bottom: 0;
  display: block;
  width: 400px;
}
<table>
  <tr>
    <td><a href="https://google.com">First column</a></td>
    <td>Second column</td>
    <td>Third column</td>
  </tr>
  <tr>
    <td><a href="https://stackoverflow.com">First column</a></td>
    <td>Second column</td>
    <td>Third column</td>
  </tr>
</table>
passatgt
  • 4,234
  • 4
  • 40
  • 54
  • This looks rather elegant. BUT the google link demo does not work. Stackoverflow one does. Probably just Google being arses as they often are. Maybe link to Bing :-) Serves them right. Anyhow v nice and tidy solution. – BeNice Dec 16 '19 at 23:18
  • This works me!! Nice solution. One thing to note is that the width for a:before has to be long enough to cover the table. – Arst Jun 08 '20 at 00:59
  • 1
    Great, but my table doesn't have a fixed width. So I just made the anchor really wide -- 4000px. Voila! – Brett Donald Jan 17 '21 at 20:00
  • @BrettDonald you could use 100vh as the width, so its the same width as the viewport :) – passatgt May 11 '21 at 08:56
  • 2
    Thanks @passatgt, I came to the same conclusion last week. 4000px had some unwanted side effects, but 100vw (not 100vh) works beautifully. – Brett Donald May 12 '21 at 11:25
  • Hmm. A bit old conversation, but can't you just put `position: relative` on the `tr` instead and use 100% width? Seems to work on the major browsers. – Magnus Gustavsson Aug 31 '23 at 10:21
  • That doesn't work for some reason in Safari, where i tested. And still not working: https://jsfiddle.net/xeo2j7v0/ – passatgt Sep 01 '23 at 21:17
8

You can use this bootstrap component:

http://jasny.github.io/bootstrap/javascript/#rowlink

Jasny Bootstrap

The missing components for your favorite front-end framework.

<table class="table table-striped table-bordered table-hover">
  <thead>
    <tr><th>Name</th><th>Description</th><th>Actions</th></tr>
  </thead>
  <tbody data-link="row" class="rowlink">
    <tr><td><a href="#inputmask">Input mask</a></td><td>Input masks can be used to force the user to enter data conform a specific format.</td><td class="rowlink-skip"><a href="#">Action</a></td></tr>
    <tr><td><a href="http://www.jasny.net/" target="_blank">jasny.net</a></td><td>Shared knowledge of Arnold Daniels aka Jasny.</td><td class="rowlink-skip"><a href="#">Action</a></td></tr>
    <tr><td><a href="#rowlinkModal" data-toggle="modal">Launch modal</a></td><td>Toggle a modal via JavaScript by clicking this row.</td><td class="rowlink-skip"><a href="#">Action</a></td></tr>
  </tbody>
</table>

Usage

Via data attributes

Add class .rowlink and attribute data-link="row" to a <table> or <tbody> element. For other options append the name to data-, as in data-target="a.mainlink" A cell can be excluded by adding the .rowlink-skip class to the <td>.

Via JavaScript

Call the input mask via javascript:

$('tbody.rowlink').rowlink()
phlegx
  • 2,618
  • 3
  • 35
  • 39
8

You can add the button role to a table row and Bootstrap will change the cursor without any css changes. I decided to use that role as a way to easily make any row clickable with very little code.

Html

<table class="table table-striped table-hover">
     <tbody>
          <tr role="button" data-href="#">
               <td>Cell 1</td>
               <td>Cell 2</td>
               <td>Cell 3</td>
          </tr>
     </tbody>
</table>

jQuery

$(function(){
     $(".table").on("click", "tr[role=\"button\"]", function (e) {
          window.location = $(this).data("href");
     });
});

You can apply this same principle to add the button role to any tag.

Todd Skelton
  • 6,839
  • 3
  • 36
  • 48
  • wow it actually worked with ui-sref instead data-href without the jquery code. need to just change cursor to finger. – nurp Jul 17 '19 at 12:40
7

There is a nice way to technically do it with <a> tag inside <tr>, which might be semantically incorrect (might give you a browser warning), but will work with no JavaScript/jQuery required:

<!-- HTML -->
<tbody>
  <tr class="bs-table-row">
     <td>Blah Blah</td>
     <td>1234567</td>
     <td>£158,000</td>
     <a class="bs-row-link" href="/your-link-here"></a>
  </tr>
</tbody>

/* CSS */
.bs-table-row {
  position: 'relative';
}

.bs-row-link {
  position: 'absolute';
  left: 0;
  height: '36px'; // or different row height based on your requirements
  width: '100%';
  cursor: 'pointer';
}

PS: Notice the trick here is to put <a> tag as last element, otherwise it will try to take the space of the first <td> cell.

PPS: Now your entire row will be clickable and you can use this link to open in new tab as well (Ctrl/CMD+click)

Ronen
  • 734
  • 1
  • 9
  • 14
6

A very easy option is just use on-click, and more correct, in my point of view, because this separate the view and controller, and you don't need to hard code the URL or whatever more you need do accomplish with the click. It works with Angular ng-click too.

<table>
  <tr onclick="myFunction(this)">
    <td>Click to show rowIndex</td>
  </tr>
</table>

<script>
function myFunction(x) {
    alert("Row index is: " + x.rowIndex);
}
</script>

Exemple working here

Wendell Pereira
  • 142
  • 1
  • 3
  • 9
  • 1
    Surely this is the correct answer. The others are crazily complex for such a simple thing. If you want to change the mouse pointer you can add tr:hover { cursor: pointer; } to your CSS class – Tom Close Jul 22 '19 at 06:41
  • 3
    @TomClose Depending on what you want the row click to do, this can be problematic as e.g. navigation won't work normally - no shift clicks for open in new tab/window, no hover to see destination, etc. – NetMage Nov 18 '19 at 20:26
5

You can use onclick javascript method in tr and make it clickable, also if you need to build your link due to some details you can declare a function in javascript and call it in onclick, passing some values.

Anahit Serobyan
  • 432
  • 1
  • 6
  • 17
5

Here is a way by putting a transparent A element over the table rows. Advantages are:

  • is a real link element: on hover changes pointer, shows target link in status bar, can be keyboard navigated, can be opened in new tab or window, the URL can be copied, etc
  • the table looks the same as without the link added
  • no changes in table code itself

Disadvantages:

  • size of the A element must be set in a script, both on creation and after any changes to the size of the row it covers (otherwise it could be done with no JavaScript at all, which is still possible if the table size is also set in HTML or CSS)

The table stays as is:

<table id="tab1">
<tbody>
        <tr>
            <td>Blah Blah</td>
            <td>1234567</td>
            <td>£158,000</td>
        </tr>
</tbody>
</table>

Add the links (for each row) via jQuery JavaScript by inserting an A element into each first column and setting the needed properties:

// v1, fixed for IE and Chrome
// v0, worked on Firefox only
// width needed for adjusting the width of the A element
var mywidth=$('#tab1').width();

$('#tab1 tbody>tr>td:nth-child(1)').each(function(index){
    $(this).css('position',  'relative');// debug: .css('background-color', '#f11');
    // insert the <A> element
    var myA=$('<A>');
    $(this).append(myA);
    var myheight=$(this).height();

    myA.css({//"border":'1px solid #2dd', border for debug only
            'display': 'block',
            'left': '0',
            'top': '0',
            'position':  'absolute'
        })
        .attr('href','the link here')
        .width(mywidth)
        .height(myheight)
        ;
    });

The width and height setting can be tricky, if many paddings and margins are used, but in general a few pixels off should not even matter.

Live demo here: http://jsfiddle.net/qo0dx0oo/ (works in Firefox, but not IE or Chrome, there the link is positioned wrong)

Fixed for Chrome and IE (still works in FF too): http://jsfiddle.net/qo0dx0oo/2/

David Balažic
  • 1,319
  • 1
  • 23
  • 50
5

I know someone has written pretty much the same already, however my way is the correct way (div cannot be child of A) and also it's better to use classes.

You can imitate a table using CSS and make an A element the row

<div class="table" style="width:100%;">
  <a href="#" class="tr">
    <span class="td">
      cell 1
    </span>
    <span class="td">
      cell 2
    </span>
  </a>
</div>

css:

.table{display:table;}
.tr{display:table-row;}
.td{display:table-cell;}
.tr:hover{background-color:#ccc;}
Sidupac
  • 651
  • 7
  • 11
4

This code bellow will make your whole table clickable. Clicking the links in this example will show the link in an alert dialog instead of following the link.

The HTML:

Here's the HTML behind the above example:

    <table id="example">
    <tr>
     <th>&nbsp;</th>
     <th>Name</th>
     <th>Description</th>
     <th>Price</th>
   </tr>
   <tr>
     <td><a href="apples">Edit</a></td>
     <td>Apples</td>
     <td>Blah blah blah blah</td>
     <td>10.23</td>
   </tr>
    <tr>
     <td><a href="bananas">Edit</a></td>
     <td>Bananas</td>
     <td>Blah blah blah blah</td>
     <td>11.45</td>
   </tr>
   <tr>
     <td><a href="oranges">Edit</a></td>
     <td>Oranges</td>
     <td>Blah blah blah blah</td>
     <td>12.56</td>
   </tr>
    </table>

The CSS

And the CSS:

    table#example {
    border-collapse: collapse;   
}
#example tr {
    background-color: #eee;
    border-top: 1px solid #fff;
}
#example tr:hover {
    background-color: #ccc;
}
#example th {
    background-color: #fff;
}
#example th, #example td {
    padding: 3px 5px;
}
#example td:hover {
    cursor: pointer;
}

The jQuery

And finally the jQuery which makes the magic happen:

    $(document).ready(function() {

    $('#example tr').click(function() {
        var href = $(this).find("a").attr("href");
        if(href) {
            window.location = href;
        }
    });

});

What it does is when a row is clicked, a search is done for the href belonging to an anchor. If one is found, the window's location is set to that href.

Aydan Aleydin
  • 157
  • 2
  • 15
3

i would prefer to use onclick="" attribute as it is easy to use and understand for newbie like

 <tr onclick="window.location='any-page.php'">
    <td>UserName</td>
    <td>Email</td>
    <td>Address</td>
</tr>
Ali Raza
  • 673
  • 8
  • 19
3

Here's an article that explains how to approach doing this in 2020: https://www.robertcooper.me/table-row-links

The article explains 3 possible solutions:

  1. Using JavaScript.
  2. Wrapping all table cells with anchorm elements.
  3. Using <div> elements instead of native HTML table elements in order to have tables rows as <a> elements.

The article goes into depth on how to implement each solution (with links to CodePens) and also considers edge cases, such as how to approach a situation where you want to add links inside you table cells (having nested <a> elements is not valid HTML, so you need to workaround that).

As @gameliela pointed out, it may also be worth trying to find an approach where you don't make your entire row a link, since it will simplify a lot of things. I do, however, think that it can be a good user experience to have an entire table row clickable as a link since it is convenient for the user to be able to click anywhere on a table to navigate to the corresponding page.

Robert Cooper
  • 2,160
  • 1
  • 9
  • 22
2

Another option using an <a>, CSS positions and some jQuery or JS:

HTML:

<table>
<tr>
    <td>
        <span>1</span>
        <a href="#" class="rowLink"></a>
    </td>
    <td><span>2</span></td>
</tr>
</table>

CSS:

table tr td:first-child {
    position: relative;
}
a.rowLink {
    position: absolute;
    top: 0; left: 0;
    height: 30px;
}
a.rowLink:hover {
    background-color: #0679a6;
    opacity: 0.1;
}

Then you need to give the a width, using for example jQuery:

    $(function () {
        var $table = $('table');
            $links = $table.find('a.rowLink');

        $(window).resize(function () {
            $links.width($table.width());
        });

        $(window).trigger('resize');
    });
Yisela
  • 6,909
  • 5
  • 28
  • 51
2

The accepted answer is great, but I propose a small alternative if you don't want to repeat the url on every tr. So you put the url or href in the table data-url and not the tr.

<table data-click data-url="href://blah">    
    <tbody>
        <tr id ="2">
            <td>Blah Blah</td> <td>1234567</td> <td>£158,000</td>
        </tr>
        <tr id ="3">
            <td>Blah Blah</td> <td>1234567</td> <td>£158,000</td>
        </tr>
    </tbody>
    </table

jQuery(document).ready(function($) {
    $('[data-click] tbody tr').click(function() {
        var url = $(this).closest('table').data("url");
        var id = $(this).closest('tr').attr('id');
        window.location = url+"?id="+id);
    });
});

This is also good because you don't need to add the click data attribute to every tr either. The other good thing is that we are not using a class to trigger a click as classes should only really be used for styling.

Thomas Williams
  • 1,528
  • 1
  • 18
  • 37
2
<tbody>
    <tr data-href='www.bbc.co.uk'>
        <td>Blah Blah</td>
        <td>1234567</td>
        <td>£158,000</td>
    </tr>
    <tr data-href='www.google.com'>
        <td>Blah Blah</td>
        <td>1234567</td>
        <td>£158,000</td>
    </tr>
</tbody>

<script>
    jQuery(document).ready(function ($) {
        $('[data-href]').click(function () {
            window.location = $(this).data("href");
        });
    });
</script>

Whilst the main solution on here is great, my solution removes the need for classes. All you need to do is add the data-href attribute with the URL in it.

Christopher Vickers
  • 1,773
  • 1
  • 14
  • 18
2

I've invested a lot of time trying to solve this problem.

There are 3 approaches:

  1. Use JavaScript. The clear drawbacks: it's not possible to open a new tab natively, and when hovering over the row there will be no indication on status bar like regular links have. Accessibility is also a question.

  2. Use HTML/CSS only. This means putting <a> nested under each <td>. A simple approach like this fiddle doesn't work - Because the clickable surface is not necessarily equal for each column. This is a serious UX concern. Also, if you need a <button> on the row, it is not valid HTML to nest it under <a> tag (although browsers are ok with that).

    I've found 3 other ways to implement this approach. First is ok, the other two are not great.

    a) Have a look on this example:

    tr {
      height: 0;
    }
    
    td {
      height: 0;
      padding: 0;
    }
    
    /* A hack to overcome differences between Chrome and Firefox */
    @-moz-document url-prefix() {
      td {
        height: 100%;
      }
    }
    
    a {
      display: block;
      height: 100%;
    }
    

    It works, but due to inconsistencies between Chrome and Firefox it requires browser-specific hack to overcome the differences. Also Chrome will always align the cell content to the top, which can cause problems with long texts, especially if varying line heights are involved.

    b) Setting <td> to { display: contents; }. This leads to 2 other problems:

    b1. If someone else tries to style directly the <td> tag, like setting it to { width: 20px; }, we need to pass that style somehow to the <a> tag. We need some magic to do that, probably more magic than in the Javascript alternative.

    b2. { display: contents; } is still experimental; specifically it's not supported on Edge.

    c) Setting <td> to { height: --some-fixed-value; }. This is just not flexible enough.

  3. The last approach, which I recommend to seriously thinking of, is to not using clickable rows at all. Clickable rows is not a great UX experience: it's not easy to visually mark them as clickable, and it poses challenges when multiple parts are clickable within the rows, like buttons. So a viable alternative could be to have an <a> tag only on the first column, displayed as a regular link, and give it the role of navigating the whole row.

gamliela
  • 3,447
  • 1
  • 35
  • 41
1

Here's a generic approach. Define this css:

// css
td a.linker {
    color:#212529;
    display: block;
    padding: 16px;
    text-decoration: none;
}

Then place this inside each td:

<td>
  <a class="linker" href="www.google.com"> 
    Cell content goes here 
  </a>
</td>
stevec
  • 41,291
  • 27
  • 223
  • 311
1

A 2023 answer: You can add an addEventListener to the row:

var rows = document.getElementsByTagName('table')[0].rows;
Array.from(rows).forEach(row => {
  row.addEventListener("click", function() {
    console.log(this.getAttribute('data-href'));
    // window.location.href = this.getAttribute('data-href');
  });
});
body {
  display: flex;
  justify-content: center;
  margin-top: 20px;
  color: #37559d;
}

a {
  color: #5165ff;
}

table {
  border-collapse: collapse;
}

tr:hover {
  background: #f2f3ff;
  outline: none;
  cursor: pointer;
}

td {
  border: 2px solid #ccd2ff;
  position: relative;
  padding: 18px;
}
<table>
  <tbody>
    <tr data-href="https://www.google.com">
      <td>One</td>
      <td>Two</td>
      <td>Three</td>
      <td>Four</td>
      <td>
        <a href="#link1">Link</a>
      </td>
    </tr>
    <tr data-href="https://www.amazon.com">
      <td>One</td>
      <td>Two</td>
      <td>Three</td>
      <td>Four</td>
      <td>
        <a href="#link2">Link</a>
      </td>
    </tr>
    <tr data-href="https://www.stackoverflow.com">
      <td>One</td>
      <td>Two</td>
      <td>Three</td>
      <td>Four</td>
      <td>
        <a href="#link3">Link</a>
      </td>
    </tr>
  </tbody>
</table>
Yanga
  • 2,885
  • 1
  • 29
  • 32
0

Here is another way...

The HTML:

<table>
<tbody>
       <tr class='clickableRow'>
       <td>Blah Blah</td>
       <td>1234567</td>
       <td>£158,000</td>
        </tr>
</tbody>
</table>

The jQuery:

$(function() {
      $(".clickableRow").on("click", function() {
          location.href="http://google.com";

      });

});
klewis
  • 7,459
  • 15
  • 58
  • 102
0
<table>
  <tr tabindex="0" onmousedown="window.location='#';">
    <td>1</td>
    <td>2</td>
    <td>3</td>
  </tr>
</table>

Replace # with the url, tabindex="0" makes any element focusable

27px
  • 430
  • 5
  • 16
  • 2
    Users of this event should note that in Chromium based browsers mouse events are depreciated in favour of pointer events: https://developers.google.com/web/updates/2016/10/pointer-events – PowerAktar Jan 09 '21 at 02:13
-1

You could give the row an id, e.g.

<tr id="special"> ... </tr>

and then use jquery to say something like:

$('#special').onclick(function(){ window="http://urltolinkto.com/x/y/z";})

Peter Berg
  • 6,006
  • 8
  • 37
  • 51
  • 2
    I believe you want to use class instead of id because you're most likely going to be having multiple rows and id should only be used for one item. – Programmingjoe Oct 21 '15 at 17:31
-11

Why should we don't use "div" tags....

<div>

  <a href="" >     <div>  Table row  of content here..  </div>    </a>

</div>
Ramesh J
  • 794
  • 2
  • 11
  • 24