Grow your CSS skills. Land your dream job.

Expanding Images using HTML5’s contenteditable tabindex

Published by Chris Coyier

HTML5 has a new attribute, contenteditable, which can be applied to any element which allows it to be edited directly in the browser window. Think of text input with a predefined value, but it can literally be any element. Form elements like text inputs support the :focus pseudo class, which allow us to style those elements when they are clicked upon or otherwise navigated to. Giving an element the contenteditable attribute means it also now supports the :focus pseudo class, which opens up some interesting possibilities!

We'll exploit this little trick to make an expanding image (like a lightbox without the overlay) right within some content.

UPDATE: Even better, you can give attributes a tabindex attribute, like you would a form element, which allow allows :focus without the editability. This article has been updated to go that route instead.

HTML5 Markup

HTML5 has nice elements for including captioned images.

<section class="image-gallery">

      <img src="images/img-1.jpg" alt="jump, matey" />


We just give the figure element tabindex, so that it can be in focus.

<figure tabindex=1>

Give each subsequent figure a tabindex value one higher and the images will be able to be tabbed through nicely from the keyboard!

The Images

The images will be "full size".

This means they will be scaled down for regular display on the page, and scaled up when we do our magical CSS expanding. Potentially a waste of bandwidth for the browsers that don't support this. The tradeoff is your call.


Normal display:

figure { 
  width: 120px; 
  float: left; 
  margin: 0 20px 0 0; 
  background: white;
  border: 10px solid white; 
  -webkit-box-shadow: 0 3px 10px #ccc; 
  -moz-box-shadow: 0 3px 10px #ccc;
  -webkit-transform: rotate(5deg); 
  -moz-transform: rotate(5deg);
  -webkit-transition: all 0.7s ease; 
  -moz-transition: all 1s ease;
  position: relative;

figcaption { 
  text-align: center; 
  display: block; 
  font-size: 12px; 
  font-style: italic; 

figure img { 
  width: 100%; /* Scale down */

The :focus part of this isn't CSS3, the but shadows, transforms, and transitions are. The hover state will rotate the image a bit, and the :focus style (when the image is clicked on), will expand it, rotate it again, and make sure it's on top with z-index.

figure:hover {
  -webkit-transform: rotate(-1deg); -moz-transform: rotate(1deg);
  -webkit-box-shadow: 0 3px 10px #666; -moz-box-shadow: 0 3px 10px #666;

figure:focus {
  outline: none;
  -webkit-transform: rotate(-3deg) scale(2.5); -moz-transform: rotate(-3deg) scale(2.5);
   -webkit-box-shadow: 0 3px 10px #666; -moz-box-shadow: 0 3px 10px #666;
  z-index: 9999;

Browser Compatibility

The HTML5 contenteditable attribute is supported in Firefox 3.6+, Safari 4+, Chrome, and Opera (10.6 only tested). Note that the attribute will cascade down to all child elements. In our demo, having the image and figure caption be editable doesn't make much sense, so we can turn it off individually on them.

<figure contenteditable="true">
  <img src="images/img-1.jpg" alt="jump, matey" contenteditable="false" />
  <figcaption contenteditable="false">Jump!</figcaption>

If you forget to turn off the editablity of the images, Firefox can look a bit funky giving you resize handles for images. Update: another reason to use tabindex instead.

Opera respects the child elements not being editable, but still runs the spellchecker on them and will red-underline words it finds misspelled which can be a bit weird.

Our demo also relies upon transforms to "work" though, which are only supported in current WebKit browsers and Firefox 4+. Firefox 3.6 supports the transform but not the transition.

The fallback is that the images just don't expand though, which is of course no big deal.

Demo & Download

View Demo   Download Files


  • If you are looking for a pure CSS lightbox, including the overlay, check out Stu Nicholls version.
  • If you need your lightbox to be fully cross browser compatible, use JavaScript like the Colorbox plugin for jQuery.


Big thanks to Adrian Sinclair who contacted me about this idea and helped with everything.


  1. Permalink to comment#


    can we rotate the image in z-coordinate (3D) ?

    if i ain’t mistake, using

    -moz-transform: matrix(a, c, b, d, tx, ty)

  2. Permalink to comment#

    Not so downloadable for now… ;-)

    Thanks anyway.

  3. SpeedGun
    Permalink to comment#

    I personally do not like this technique because you can remove the images from the light box (because of the content editable attribute).

    But is still interesting, yet another thing you can do without Javascript.

  4. Gotta love it…and no JS!

  5. seutje
    Permalink to comment#

    the contenteditable has some unwanted repercussions, like when u click the image and hit a key, like “a”, the image will be replaced by a character “a”

    instead of using contenteditable, consider using tabindex=”-1″, which should also make it focussable (seems to work on a Chrome 6)

    • Great idea! Browser support seems to be the same. I updated the article and download to use this instead, as it’s much cleaner and adds keyboard navigation quite cleanly. I figured I’d just use tabindex values of 1-4 instead of -1, since why not have them be able to be tabbed to…

  6. Good idea to use :focus for giving specific styles, and nice demo.

    But contenteditable is the WRONG attribute to use if you want to make a random element focusable. You should be using tabindex=”0″ instead. Look it up. :)

  7. Oh, I see that someone mentioned tabindex before. Using tabindex=”-1″ (or any negative value, says HTML5) will work but the element won’t be reachable through sequential focus navigation, while with tabindex=”0″ it will. So use tabindex=”0″ if you want it to work with focus navigation (rather than clicks).

  8. Noah
    Permalink to comment#

    Great article. I didn’t know about either contenteditable or tableindex. You’re demo isn’t quite as exciting as it is in IE. Poor poor IE. When will it catch up?

  9. Permalink to comment#

    This article makes great use of CSS3 features, that’s awesome. So when do you think we should make the final move onto CSS3 given today’s significant statistics of IE users?

    I’m not sure if this is relevant, but there’s something called CSS3PIE which contends to use javascript in order to make CSS3 features IE-capable. However, my experience with it was rather terrible (aka, I couldn’t get it to work).

    • PIE only handles 3 CSS3 properties I believe…border-radius, linear gradient, and box shadow. And I got it to work just fine. It has issues though with z-index, and I am pretty sure it doesn’t work at all on form elements.

      The main thing to remember with PIE though, is that even though you are declaring it in the CSS file, it HAS to be relative to the html file. So instead of (../images/, it would have to be(images/ I’m guessing that is the problem you are having

    • Permalink to comment#

      It’s possible that this is where my flaw was. However I did read those instructions in the PIE manual and did make the path relative to the HTML document.

      I’ll give it another shot though. Thanks for the advice

    • Permalink to comment#

      Ahh I found the reason why! It’s because it doesn’t work locally (for some reason, even though it should given it’s only JS?) But when I put it on my server, it works just fine.

      Cool stuff :)

    • Permalink to comment#

      PIE is *the* solution for IE css3. Highly recommended.

  10. Robert
    Permalink to comment#

    So I’m assuming the anti-aliasing issues largely stem from subpixel rendering technologies not being as bleeding edge as HTML5, right? Because even with ClearType the fracturing looks awfully unprofessional. Now don’t me wrong, I like the concept, but like most things HTML5 it’s just not ready for mainstream usage.

    • The aliasing is an issue with Chrome (and Webkit presumably) on the images and with Firefox on the text (but interestingly, Chrome shows the text fine and Firefox shows the images nicely).

      It’s not really anything to do with subpixel rendering – they simply aren’t anti-aliasing rotated images (Chrome) or text (FF). The jagged edges are aliasing artefacts.

  11. Amazing example, with no JS, only pure html5 and css3 – i love that. Thank you.

  12. Do most CMS editors have the ability to resize an image one a user places it? If not, then that could be a use for the contentedible on an img. Let’s say the client uploads a freakin huge image, then places it in the content, and you have it so that all img tags get contenteditable set to true, you could use javascript to grab the height and width after they resize it with the bounding box, and use those numbers for what size the img displays at. Make sense?

    And does anyone know if the HTML5 IE shiv handles these new attributes? Or is it just elements? I haven’t used it, and only heard of it. If it does, you could use CSS PIE, and the shiv, to get everything but the CSS3 transform to work in IE then. At least that is what I am thinking.

    Of course that is a lot of crap to go through just to get IE to work somewhat like the other browsers.

    • Ok, in reply to myself, and anyone else that cares. The shiv does indeed get the attributes to work. For IE7, if you have contenteditable set to true on an image, you need a min-height on it or you won’t be able to adjust the img height wise. Didn’t try it in 6. IE8 works fine without the min-height.

      And ignore the “could use PIE and…” in my comment above. Mind blanked there. Without transform, having the focus available doesn’t mean crap.

    • Thanks for looking up whether shiv handles the new attributes, was wondering about that one.

      Great article btw Chris!

  13. Shut Pavel
    Permalink to comment#

    Sorry, but why aren’t you adding -o- and unprefixed rules?

    This way when browsers support the properties without prefixes you won’t see the effects!

    • Permalink to comment#

      I came here to ask this. Is ‘transform’ instead of just ‘-moz/-webkit-transform’ a good way to future-proof?

  14. I found a way to make this work in ie if javascript is enabled, cssSandPaper is a css “plugin” in javascript that allows transforms in ie, using filters (those thing used to make ie6 load png24 and for opacity in ie), I’m not quite sure how to use it, but it’s worth a shot!

  15. Permalink to comment#

    Liking this, especially with the tabindex improvement.

    A timely reminder too that somehow I need to override WordPress gallery output to use this structure (I’m not a programmer, PHP or otherwise).

    Thanks, Karl

  16. Very good idea.
    Thank you for this article.

    I try to improve it giving an overlay effect in background :

    Hope you’ll visit it.

    Thanks, Geoffrey.

  17. Kawohi
    Permalink to comment#

    Hey Chris! Great article! But a little grammar mistake :)

    “The :focus part of this isn’t CSS3, the but shadows, transforms, and transitions are”

    Great article though! Thanks!

  18. Permalink to comment#

    Why you’re not using -o-transform, -o-transition and box-shadow properties to make this work on Opera too?

  19. Hey Chris,

    Nice tutorial :)
    Great to see this being built without the use of javascript, don’t get me wrong, I really like javascript but reducing download time is starting to become really beneficial for SEO.

    Such a shame about IE and html5/CSS3 :(
    I would love to build sites using all of these new features but until IE catches up It’s a bit of a no go as a good percentage of web users still use IE and sites just would not look as good as I want them to. +most of the people that I design the sites for use IE so couldn’t really sell them the amazing features their site packs!

  20. Victor Oliveira
    Permalink to comment#

    Looks like full on Wuffoo Battlefield!!! LOL

    Nice article as always!!

  21. klickreflex
    Permalink to comment#

    Totally Awesome! Thank you :)

  22. Permalink to comment#

    Maybe it was named before but I could not find it…
    Safari 5 does anything wired with the shadow and the font… Let me call it “baa” (bad anti-aliasing).

    The baa isn’t a Webkit-problem I think because it does not appear in Chome 5. It comes up when the transition-methode is called. After the animation everything is great again.

    Anyway. It’s great. Thanks, Chris.

  23. Permalink to comment#

    Fantastic, as always, Chris. I tried it out on a page from data acquired in Northern Minnesota this July. (I now live in NYC and the heat was killing me.)
    Funny thing, when I added a Vimeo video link, the Zoomed type does not Focus in Safari. But it does in Firefox.
    See here: (without video)
    and with video: (caption type on Zoomed photo is Wack)
    What could cause that? Why would a plug-in to that?
    Hope you are having a great summer cause you deserve it. Thanks for the tutorial.
    PS: I still haven’t heard if Brett is playing this year, have you?

  24. Tomas
    Permalink to comment#

    Firefox 3.6 have no animation. Chrome 6 has no antiantlias. Half of visitors (IE) can’t see at all.

    How about using Flash that has everything and work in 98% of browsers? And do a simple fallback instead of mess up everything?

  25. Santi Maspons
    Permalink to comment#

    In Safari for IOS works nice but is not possible to return to normal scale!

  26. barney
    Permalink to comment#

    Love this way of having expanding images however what if I want a hyperlink in the figcaption? Upon clicking on an anchor tag focus is lost and I have been unable to find a way to get it to work.

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".