simonewebdesign

How to make a real-time in-browser editor with HTML5′s contenteditable

Lots of fun here. Some days ago I just read a very cool comment on html5doctor:

Here is a fun example with the contenteditable attribute.

Just paste this data-url to your browser and then edit the title or the style of the whole page

data:text/html,<title contenteditable>Hello World</title> <style contenteditable>head, title, style {display: block;}</style>

Another thing is that you can create a notepad with just one short url:

data:text/html,<html contenteditable></html>

Pretty cool I think.

Cat with eyes shining bright This just made my eyes shine brighter than ever. I think there’s a lot of potential here: do you imagine how many things you could realize with the contenteditable attribute?

For example, you can even do this:

script {
  display: block;
}

The result? A JavaScript in-browser editor.


Can I really build an HTML5 editor in my browser?

Absolutely. This tutorial is focused on how to build a simple but powerful editor, directly within your browser, making it possible to edit your page content in real time. It may sound like a lot of work, but don’t worry: actually it’s easier than it seems, for two main reasons:

  1. The browser already shows content in real time. When you open Firebug on Firefox, Chrome DevTools, Opera Dragonfly, or whatever, and you edit the CSS or JS, the browser automatically re-renders its window.
  2. You don’t need any parser. Again, and unsurprisingly, the browser is already capable to interpret your code.

In fewer words, this means you already have the tools. Just use your imagination to build something awesome.

In this tutorial I won’t talk about everything, but only of the problems I’ve encountered while building an editor, and how to solve them.

Displaying the <script> and <style> tags

This is actually very simple. You only need to match them by CSS, and apply display: block to them. For example:

style, script {
  display: block;
}

However I’d recommend to apply this rule only to the elements that have the contenteditable attribute. You can do this with:

[contenteditable] {
  /* will match all elements with contenteditable attribute */
  display: block;
}

How to make it look like real code

Real editors use monospace fonts. We can also make <script> and <style> behave like the <pre> tag. All we need is the following code.

style, script {
  font-family: monospace;  /* monospace font */
  white-space: pre;        /* behave like <pre> */
}

You can even install a syntax highlighter like the Google code prettify, if you want.

Make the page title editable

This one is real fun. It’s ridicolously easy to show the title directly in the browser, but pay attention because the <title> tag is inside <head>, that is hidden by default! So you must display the title and the head, as a block:

head, title {
  display: block;
}

Then just make it contenteditable and you’re done.

<title contenteditable>The page title</title>

Executing the JavaScript in real time

Now the tricky part. Your scripts actually get executed only the first time, on page load. So the question is, how can we re-execute the JavaScript every time it changes?

Well, I’m sure there are many solutions. Mine is quite straightforward: I dynamically create a new <script> element every time the user adds something new. For the sake of simplicity I’ve created this function:

function executeCode() {
  var script = document.createElement("script");
  script.innerHTML = js.innerHTML;
  js.parentNode.insertBefore(script, js);
}
// the code we want to execute is contained here:
var js = document.getElementById('js');

Why I’ve put the js variable outside of the function? You’ll find it out soon.

We need to call the executeCode() function during an event in order make it work properly. I think the onkeyup event will be perfect in this situation: it gets fired as soon as the user has finished typing.

js.onkeyup = function(event) {
  executeCode();
};

However, this approach has a flaw. What if I type, say, alert('foobar')? I won’t see an alert, but… 15 alerts! This because the onkeyup event would get fired 15 times in this case — one for each character. How can we solve this problem?

Again, there can be many solutions. I chose to use window.setTimeout(). My implementation is fairly simple: I just tell the browser to wait 2000 milliseconds (2 seconds) before executing the new code, but if the user modifies the code in the meanwhile, I reset the timer. This is the key to prevent the code getting executed more than once.

Here’s a full example, feel free to copy-paste and try it directly in your browser:

<h1>Sample JavaScript real-time in-browser execution</h1>

<script id="js" style="display: block" contenteditable>
alert('foo'); // edit me!
</script>

<script>
(function() {

  var timer,
      js = document.getElementById('js'),
      delay = 2000;

  js.onkeyup = function(event) {

    if (typeof timer != "undefined") {

      clearTimeout(timer);
      timer = 0;
    }

    timer = setTimeout(executeCode, delay);
  };

 function executeCode() {
    var script = document.createElement("script");
    script.innerHTML = js.innerHTML;
    js.parentNode.insertBefore(script, js);
 }

})();
</script>

It’s your turn now!

I just demonstrated that it’s definitely possible to build an HTML5 editor that works directly in your browser. Imagine a full-featured WYSIWYG in-browser editor: it could potentially improve your productivity, enabling real-time collaboration and a lot more. Your only limit is your imagination.

Need inspiration?

Demo | Download

View this page on GitHub