Make a div clickable

We all dislike that links are so small, and hard to click. So of course we want to make the clickable areas bigger. Some would think that doing this with some CSS on the a-tag would be a good way, but then you can’t have block level elements inside it (you’ll get a validation error if you try to put headings or paragraph tags inside of links). So what’s a more general solution?

My take is to use a div instead, and use javascript, of course together with a good fallback. When clicking the div, find the first link inside it, and go to that URL. It’s simple, and with a few additional quirks, it gets really useful.

Javascript code (requires jQuery):

$(document).ready(function(){
   var block = $(".teaser");
   block.click(function(){
      window.location = $(this).find("a:first").attr("href")
   });
   block.addClass("clickable");
   block.hover(function(){
      window.status = $(this).find("a:first").attr("href")
   }, function(){
      window.status = ""
   })
});

CSS for showing that the div actually is clickable:

.clickable {
   cursor: pointer;
}
.clickable:hover {
   background: #efefef;
}

A clickable div demo is of course available.

How it works

  • When the div (or other tag, you choose) is clicked, find the first anchor tag, get it’s href attribute, and go there. Relying on an actual link means you always have a fallback, so no cheating.
  • When javascript is disabled, it just falls back to a regular block, where only the links are clickable.
  • A class called “clickable” is set on the block to allow for javascript-specific styling, such as changing the cursor with cursor: pointer, something you don’t want to happen when the block isn’t clickable.
  • The changing background color on hover is done with CSS, which I think is fair, considering the small percentage of users using IE6. Changing background color isn’t a must feature.
  • Lastly, since we’re simulating a link here, it should show where the link is going. I’ve done this by setting the statusbar to the link location on hover, something that’s useful when it works (users can disable this in some browsers).

Hope that little snippet is useful for someone out there, I think it’s a good example of good use of javascript.

33 responses to “Make a div clickable

  1. Great! I did some polishing (well, depending on what one is looking for):

    (function($)
    {
    $.fn.clickable = function(options)
    {
    var clickable = this;

    clickable.each(function()
    {
    var e = $(this);

    e.click(function()
    {
    window.location = $(this).find(‘a:first’).attr(‘href’)
    });

    e.hover(function()
    {
    window.status = $(this).find(‘a:first’).attr(‘href’)
    }, function()
    {
    window.status = ”
    });

    e.addClass(‘anchor’);
    });

    return clickable;
    };
    })(jQuery);

  2. It seems there are a few of us who have realised this progressive enhancement is really useful. Like Ole mentioned, my friend Leevi released his bigTarget jQuery plugin. At pretty much the same time I got my demo page up for the code I’ve been using for a while, check out my Fitted jQuery plugin which achieves similar things.

  3. @Ole, trovster, grimen: Yeah, I found your suggested plugins right after I posted. I’m not sure I need it in plugin form, I usually just use this for a couple of boxes on the start page, which means supporting a single class, and 12 lines of code, is fine. Thanks though.

  4. Why not just give links more padding? Making elements clickable that are normally not clickable leads to confusion and is not a behavior users expect.

  5. @Zach Leatherman: That’s a very valid concern. I’ll see if I can add middle-click to the snippet if I get the time. Should be possible to forward the event from the block to the link somehow.

    @Anon: What kind of confusion? These are all extra features, that make things easier for the user. If you look at the example, you’ll see that more padding just doesn’t work. Bigger clickable area (which the design should reflect, of course), means easier for user to hit it. I see only good things.

  6. @Krijn Hoetmer: That’s actually a really good idea. Why should validation put us down? The only downpart I see is that it wouldn’t allow me to have other links inside it (as in the example). Because I guess HTML5 doesn’t allow links inside links, right? But that’s not such a big issue. Looking forward to good HTML5 support in browsers.

  7. Interesting. But i hope that xhtml 2 will come faster. This will allow href attribs for any element. So making a div clickable in xhtml 2 is straightforward: <div href=”http://www.some.where.com”/>…

    The better solution i think :)

  8. @Emil: It already “validates”, when you use the HTML5 doctype. You can’t have nested links indeed, but that makes sense in a way :) And it already works cross-browser today; you only need to put

    display: block;

    on your links (and make sure to use closing

    p

    tags, etc.), so it’s one of the safe parts of the draft you can already use, imho. The only problem this doesn’t solve is making entire

    tr

    elements

    href

    able, due to table parsing and the magic that involves. You still need JavaScript for that.

  9. Also, using this, you get

    :hover

    styles for free (without using JS hacks) in IE6, since that babe only understands

    :hover

    on

    a[href]

    .

    I only wonder how search engines and AT work with this. “Click here” links clearly suck, but perhaps linking entire blocks of text, including headings, sucks as well. Would using

    title=""

    on the link solve that? Somebody should do some study in that field :)

  10. @Krijn Hoetmer: Great comments, you know a lot about stuff :) A search engine experiment with block links would be interesting. My guess is that the more words you have inside your link, the less weight each of them have. So for SEO, this might not be the most optimal solution. On the other hand, search engines care about words around a link too, so I’m not sure how much of a difference it makes.

  11. In really extreme cases (that is, 80+ teasers) further enhancements can be done by letting a global click listener do the job with event delegation.

    That will save a few buck on DOMready, especially in IE which is really slow in comparison.

  12. Brilliant! I have been doing this manually on my website for a few years, just adding an

    onClick

    event to the containing

    div

    – see website link for example. But this looks like a better solution, means I don’t need to worry about putting in the links twice every time.

    Why not just give links more padding? Making elements clickable that are normally not clickable leads to confusion and is not a behavior users expect.

    It depends on the nature of the content. In some cases, extra padding, leading or spacing will do a good job. In other cases, it helps to make surrounding content clickable. For example, on my website, there is a ‘panel’ that contains several items, and making the entire panel into a link makes it easier for users to select it – while, of course, retaining on old fasioned anchor on the first line for accessibility and spiders.

    By applying

    :hover

    properties to the

    div

    , you give the visual affordance of a link to users (hand cursor, change of colour), so there should be no problem with unexpected behaviour.

  13. Simply positioning an a-element absolutely on top of the div with a width and height of 100% would achieve the same thing, no? _And_ it would act exactly the same as a real link (as it _is_ a real link).

    I’ve done it this way before though as well, just a thought.

    Regarding the JS-only CSS; I’ve used a js-enabled/js-disabled class on the body-element for ages now and it’s perfect for things like this.

    I add the js-enabled class immediately after the opening body-tag so there’ll be no lag for the JS-only styling:

    &lt;body class="js-disabled"&gt;
    &lt;script type="text/javascript"&gt;
    document.body.className = 'js-enabled';
    &lt;/script&gt;

    As any performance-aware front-end developer I include all my JS before the _closing_ body-tag so it normally takes a couple of seconds before it kicks in. Giving body the js-enabled class at the top avoids styles blinking in though.

  14. @Andreas: It’s actually not exactly the same, as it has some strange side effects. Since the image covers all the text and images in the teaser, you can select or save the text or the image. And you can’t have more than one link in the same teaser, something that might matter for some (although few) people. On the other hand you get the possibility to middle-click the link, and all that.

    Nah, I still like the HTML5 solution (see above comment) best I think.

  15. Do you think that by using this javascript method the SEO of that page will remain the same? Google has some issues reading javascript..

    Anyway the demo looks great!

  16. @Alex: Unfortunately, there’s no easy way to do that to the whole block. Though you could right-click on the real link, and do what you want there.

  17. @Emil, sorry i noticed that the real link retains it’s capabilities only after i’ve posted my last comment.

    What i really like is that even if javascript is disabled you don’t get any error messages and the div block remains as if there is no javascript there.

  18. Thanks for this – I have a question I want to make 3 div’s like this on my page, each one with a different anchor.

    1)How do I change the code for the 3 divs?
    2)Where does the script actually go?

    Sorry for the simple questions, I’m not a programmer!

  19. @Mac: Just use several divs with the class “teaser”, no other changes is needed for it to support multiple clickable blocks.

    For a working example, and descriptions of where the script goes, check out the demo page, and copy code from there.

  20. I’ve been using this technique for a while, but I have seen some examples of people using clickable divs without including a fallback link within the div for non-JS users. However, your JS technique handles this nicely, due to pulling the href from the link contained within the div. Thanks

Comments are closed.