Today while working on a project that uses contenteditable <div> elements I got stuck on a bug for a good long time because of the crazy failure-mode it exhibited. You can try for yourself in the contenteditable below (sooner or later I hope this bug will be fixed and the example will stop working :)).

Try deleting the first character in this sentence (you won't be able to), or the last (the caret will disappear after deleting the character)

I'm working on a reasonably complex editor using Google Web Toolkit (GWT) with multiple content-editable <div> elements used to collect text input. You might be wondering why we're using contenteditable instead of <textarea> or something - well here's why:

  1. Styling contenteditable's is much easier
  2. Allowing the input area to grow to fit the contained content "just works" - this is pretty hard to do with a <textarea>, though it can be done.
  3. We can deliberately insert html into the contenteditable as the user types - for example i'm creating a tag editor, and by using a contenteditable I can render the tags nicely even as the user is typing - say, whenever the user enters a delimiter.

Of course, contenteditable's are not without problems - not least you have to deal with the html content that they produce (e.g. <p> or <div> tags produced by the enter key), and arbitrary html resulting from paste operations, but that's another story.

How the bug manifests

Anyways, I have a bunch of contenteditable's in my web-app, all seemingly working fine. Then I notice that one of them is behaving a bit strangely: if I try to delete characters from the end of the content the contenteditable loses focus after deleting one character.

Being a complex app I have all kinds of event-handlers bound to these contenteditable's, so I started removing the likely suspects one by one, trying to find the culprit.

Eventually I'd removed all the event-handlers and was scratching my head, wondering how on earth I could still have this problem on just one of my contenteditable's.

I checked in Firefox - no problem, all working. I compiled the GWT app to pure javascript and ran outside of GWT development mode, just to be sure it wasn't some weird GWT-chrome-plugin bug - still suffering. I looked for other event handlers bound higher up the DOM tree. Still no joy.

When the bug manifests

Finally - almost in desperation - I started inspecting the CSS (surely the CSS could not be causing such bizarre behaviour, right? Uh, wrong!).

After some puzzling I reduced the replication steps down to some very simple html and an unfortunate collision of CSS styles:

<html>
  <head>
    <title>bug</title>
    <style>
      .s1 { display:inline; }
      .s2 { display:table; }
    </style>
  </head>
  <body>
    <div class="s1 s2" contenteditable="true">delete me</div>
  </body>
</html>

Of course this CSS doesn't make sense - the two display settings conflict. That's easy to spot in a simple example like this, but much more difficult in a complex application with a large DOM tree and many many CSS styles.

As for the failure mode, you might expect one style to "win", and forgivably it could be a different style in different browsers.

What you really don't expect is the bizarre behaviour we experienced. The bug currently manifests in Chrome 15 (and 16 beta) on Linux, Mac and Windows(7), and is reported in the chromium issue tracker as bug 107366.

blog comments powered by Disqus