How to Create a WYSIWYG Rich Text Editor in JavaScript. Pt. 1 | WebReference

How to Create a WYSIWYG Rich Text Editor in JavaScript. Pt. 1

current pageTo page 2To page 3

How to Create a WYSIWYG Rich Text Editor in JavaScript. Pt. 1

Since the Internet was first unleashed, people have been using it to communicate with each other. It started with newsgroups and text based e-mail and has since progressed to web forums, richly formatted e-mails and more recently, blogs. A common feature of the last three is a text-box that allows the user to enter their own entry or e-mail to be either posted on to the forum or delivered to some destination. Taking a look around at what's on offer these days I have noticed one aspect of these sites that seems a bit primitive.

While users are able to compose richly formatted text with animated emoticons and many other features, there is no way to see what the finished work will look like until it is either posted or a preview is generated.

In this article I will show how a more modern look can be achieved that will allow writers to see how their text will look as they are writing it. This concept is not a new one, as WYSIWYG editors have been around for many years. They just haven't seemed to hit web pages yet.

Bold: Italic: Color: Background: Font: Size:

Basic Concepts

A text editor is a control that accepts keyboard and mouse input and displays the resulting text in some region of the screen. Implementing one will require wiring a number of collaborating HTML elements together.

The first hurdle to cross is finding the combination of elements that will work for each browser. Unfortunately, Internet Explorer and Netscape have significant differences in the ways HTML elements interact with keyboard and mouse events. In Internet Explorer, any HTML element can receive keyboard events so long as it is visible, whereas with Netscape, keyboard events are limited to a subset of HTML elements although they do not need to be visible.

For Internet Explorer, a <div> element will be enough both to display the formatted text and handle the user's input while in Netscape, the keyboard events will be caught by a hidden text box. Later on, we'll see how these parts fit together.

A vital part of any editor is the cursor; it shows the user where the text will be inserted or deleted from. In this article I've used a <span> element containing a single bar character '|'. A background timer event toggles its visibility to distinguish it from the other characters.

Finally, some mechanism is needed to store the user's text as they type in a way that will record the multiple formats and allow individual characters to be added and removed. I chose to use a <span> element to store each individual character. Insertion and deletion of characters translates to inserting and deleting the <span> elements. By modifying the style attributes of the <span> element, each character can be formatted individually.

The Code

Because of differences in the browsers, the code will sometimes need to differentiate between browsers. A Boolean variable is defined at the start to manage this task:


// test the browser

var bIsNetscape = (navigator.appName == "Netscape");


The editor is managed fully by a single JavaScript class called "RichEdit". The constructor (below) has arguments for name, text-box style, initial character style and some initial text.


function RichEdit(name, editStyle, charStyle, sText)


  // initialize some internal values

  this.bInFocus = false;


The charStyle argument defines the initial style settings to use for new characters. It also defines the set of styles that the RichEdit code will process, more on this later.


  // save the character style for later = charStyle;


The RichEdit object is designed to be instantiated inline with the HTML page load, so the first thing that must be done is to create a place to insert the RichEdit controls, this will be called the insertion point as the rest of the code will use this place to insert HTML elements onto the page.


  // create an insertion point.

  document.write('<div id="' + name + '"></div>');

  this.oInsertionPoint = document.getElementById(name);


Once the insertion point is created, standard DOM methods are used to insert further elements. The first element to go in is the ‘text' box, which is modeled using a <div> element. The editStyle argument is applied to the <div> to give it the desired look and feel and the supplied text is inserted


  // the 'text' box - or where the text goes

  this.oDiv = document.createElement('div');


  // set the styles

  this.copyStyle(this.oDiv, editStyle); = "auto"; = "break-word";


  // insert the text

  if ( sText ) this.setHTML(sText);


  // link back to this object

  this.oDiv.oRichEdit = this;


Now to handle user inputs. This is the point where Internet Explorer and Netscape diverge. As mentioned above, Netscape will not deliver keyboard events to <div> elements so I've used an invisible floating <input> element to capture these events. This <input> element is stored within a <span> element and inserted into the page. With this in place, event handlers can be added to the <input> element to capture the keyboard input. The RichEdit control needs to attach handlers to the onfocus and onblur events. These events signal when the user's input becomes directed to the control and when it leaves.


  // handle clicks

  this.oDiv.onclick = RichEdit.prototype.onDivClick;


  if ( bIsNetscape )


     // In Netscape, <div> elements don't have keyboard events, so

     // create a small, hidden text <input> box to catch them

     var oTextSpan = document.createElement('span'); = 'absolute'; = 'hidden';


    this.oTextbox = document.createElement('input');

    this.oTextbox.type = 'text'; = "1px";




     // add event handlers

    this.oTextbox.oRichEdit = this;

    this.oTextbox.onkeypress = RichEdit.prototype.onKeyPress;

    this.oTextbox.onfocus = RichEdit.prototype.onDivFocus;

    this.oTextbox.onblur = RichEdit.prototype.onDivBlur;






current pageTo page 2To page 3

Created: March 27, 2003
Revised: February 2, 2005