YUI recommends YUI3.
YUI 2 has been deprecated since 2011. This site acts as an archive for files and documentation.
This documentation is no longer maintained.
The Rich Text Editor is a UI control that replaces a standard HTML textarea; it allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images. The Rich Text Editor's toolbar is extensible via a plugin architecture so that advanced implementations can achieve a high degree of customization.
In order to give you the greatest possible control over the size and performance of the Rich Text Editor codebase, we provide two versions of the Editor module and two versions of the buttons that live on the Toolbar:
Choose the right combination of features in your Editor and Toolbar to get the right tradeoff between size and richness for your application.
In this 36 minute video, YUI Rich Text Editor author Dav Glass takes you on a guided tour of the component, including both how to use and how to extend the base functionality. [iPod/iPhone compatible download also available.]
To use the Editor, include the following source files in your web page:
<!-- Skin CSS file --> <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.9.0/build/assets/skins/sam/skin.css"> <!-- Utility Dependencies --> <script src="http://yui.yahooapis.com/2.9.0/build/yahoo-dom-event/yahoo-dom-event.js"></script> <script src="http://yui.yahooapis.com/2.9.0/build/element/element-min.js"></script> <!-- Needed for Menus, Buttons and Overlays used in the Toolbar --> <script src="http://yui.yahooapis.com/2.9.0/build/container/container_core-min.js"></script> <script src="http://yui.yahooapis.com/2.9.0/build/menu/menu-min.js"></script> <script src="http://yui.yahooapis.com/2.9.0/build/button/button-min.js"></script> <!-- Source file for Rich Text Editor--> <script src="http://yui.yahooapis.com/2.9.0/build/editor/editor-min.js"></script>
<!-- Skin CSS file --> <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.9.0/build/assets/skins/sam/skin.css"> <!-- Utility Dependencies --> <script src="http://yui.yahooapis.com/2.9.0/build/yahoo-dom-event/yahoo-dom-event.js"></script> <script src="http://yui.yahooapis.com/2.9.0/build/element/element-min.js"></script> <!-- Needed for Menus, Buttons and Overlays used in the Toolbar --> <script src="http://yui.yahooapis.com/2.9.0/build/container/container_core-min.js"></script> <script src="http://yui.yahooapis.com/2.9.0/build/menu/menu-min.js"></script> <script src="http://yui.yahooapis.com/2.9.0/build/button/button-min.js"></script> <!-- Source file for Rich Text Editor--> <script src="http://yui.yahooapis.com/2.9.0/build/editor/editor-min.js"></script>
To use the SimpleEditor, include the following source files in your web page:
<!-- Skin CSS file --> <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.9.0/build/assets/skins/sam/skin.css"> <!-- Utility Dependencies --> <script src="http://yui.yahooapis.com/2.9.0/build/yahoo-dom-event/yahoo-dom-event.js"></script> <script src="http://yui.yahooapis.com/2.9.0/build/element/element-min.js"></script> <!-- Needed for Menus, Buttons and Overlays used in the Toolbar --> <script src="http://yui.yahooapis.com/2.9.0/build/container/container_core-min.js"></script> <!-- Source file for Rich Text Editor--> <script src="http://yui.yahooapis.com/2.9.0/build/editor/simpleeditor-min.js"></script>
<!-- Skin CSS file --> <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.9.0/build/assets/skins/sam/skin.css"> <!-- Utility Dependencies --> <script src="http://yui.yahooapis.com/2.9.0/build/yahoo-dom-event/yahoo-dom-event.js"></script> <script src="http://yui.yahooapis.com/2.9.0/build/element/element-min.js"></script> <!-- Needed for Menus, Buttons and Overlays used in the Toolbar --> <script src="http://yui.yahooapis.com/2.9.0/build/container/container_core-min.js"></script> <!-- Source file for Rich Text Editor--> <script src="http://yui.yahooapis.com/2.9.0/build/editor/simpleeditor-min.js"></script>
yui-skin-sam
class name to an element that is a parent of the element
in which the Rich Text Editor lives. You can usually accomplish this simply by putting the class on the
<body>
tag:
<body class="yui-skin-sam">
<body class="yui-skin-sam">
For more information on skinning YUI components and making use of default skins, see our Understanding YUI Skins article here on the website.
Instead of copying and pasting the filepaths above, try letting the YUI dependency Configurator determine the optimal file list for your desired components; the Configurator uses YUI Loader to write out the full HTML for including the precise files you need for your implementation.
Note: If you wish to include this component via the YUI Loader, its module name is editor
. (Click here for the full list of module names for YUI Loader.)
Where these files come from: The files included using the text above will be served from Yahoo! servers. JavaScript files are minified, meaning that comments and white space have been removed to make them more efficient to download. To use the full, commented versions or the -debug
versions of YUI JavaScript files, please download the library distribution and host the files on your own server.
Order matters: As is the case generally with JavaScript and CSS, order matters; these files should be included in the order specified above. If you include files in the wrong order, errors may result.
This section describes several common uses of the Rich Text Editor. It contains these subsections:
The SimpleEditor Control is a smaller more basic version of the Editor Control. Most of the editing features found in the main Editor Control exist in the SimpleEditor version. However a few were removed:
YAHOO.widget.EditorWindow
— The floating panels used for image and link editingThe major difference between the two editors are their dependencies.
SimpleEditor's dependencies are:
The Rich Text Editor is designed to replace an existing HTML <textarea>
control. Users whose browsers do not support JavaScript will therefore see a standard <textarea>
in place of the Rich Text Editor. The base markup for this approach is as follows:
<body class="yui-skin-sam"> <textarea name="msgpost" id="msgpost" cols="50" rows="10"> <strong>Your</strong> HTML <em>code</em> goes here.<br> This text will be pre-loaded in the editor when it is rendered. </textarea> </body>
<body class="yui-skin-sam"> <textarea name="msgpost" id="msgpost" cols="50" rows="10"> <strong>Your</strong> HTML <em>code</em> goes here.<br> This text will be pre-loaded in the editor when it is rendered. </textarea> </body>
With this markup in place, the JavaScript to instantiate the Rich Text Editor involves a simple constructor to which is passed a configuration object. Once instantiated, you use the render
method to place the Rich Text Editor on the page:
var myEditor = new YAHOO.widget.Editor('msgpost', { height: '300px', width: '522px', dompath: true, //Turns on the bar at the bottom animate: true //Animates the opening, closing and moving of Editor windows }); myEditor.render();
var myEditor = new YAHOO.widget.Editor('msgpost', { height: '300px', width: '522px', dompath: true, //Turns on the bar at the bottom animate: true //Animates the opening, closing and moving of Editor windows }); myEditor.render();
The full list of configuration options that you can pass in your constructor can be found in the API documentation.
With the simple markup and script above, and including the skin stylesheet for Rich Text Editor, you will see rendered to your page a rich control that looks like this:
You render the SimpleEditor Control the same as the Editor Control, only you call the SimpleEditor
constructor instead.
var myEditor = new YAHOO.widget.SimpleEditor('msgpost', { height: '300px', width: '522px', dompath: true //Turns on the bar at the bottom }); myEditor.render();
var myEditor = new YAHOO.widget.SimpleEditor('msgpost', { height: '300px', width: '522px', dompath: true //Turns on the bar at the bottom }); myEditor.render();
With the simple markup and script above, and including the skin stylesheet for Rich Text Editor, you will see rendered to your page a rich control that looks like this:
There are a couple of ways to get the data from the editor. The first way is to let the Editor do it for you by setting the handleSubmit
configuration option.
Setting the handleSubmit
configuration option, the Editor will attempt to attach itself to its parent form's submit event. Then it will call its saveHTML
method, then proceed with the form submission.
The manual way, is to call the saveHTML
method yourself. Like this:
var myEditor = new YAHOO.widget.Editor('msgpost'); myEditor.render(); //Inside an event handler after the Editor is rendered YAHOO.util.Event.on('somebutton', 'click', function() { //Put the HTML back into the text area myEditor.saveHTML(); //The var html will now have the contents of the textarea var html = myEditor.get('element').value; });
var myEditor = new YAHOO.widget.Editor('msgpost'); myEditor.render(); //Inside an event handler after the Editor is rendered YAHOO.util.Event.on('somebutton', 'click', function() { //Put the HTML back into the text area myEditor.saveHTML(); //The var html will now have the contents of the textarea var html = myEditor.get('element').value; });
The default toolbar included with the editor makes every currently supported feature available by default. You can override this config before the editor is rendered by passing in an object literal of a new toolbar to the constructor.
See this example for the full toolbar config
var myEditor = new YAHOO.widget.Editor('msgpost', { height: '200px', width: '385px', dompath: false, animate: true, toolbar: { titlebar: 'My Editor', buttons: [ { group: 'textstyle', label: 'Font Style', buttons: [ { type: 'push', label: 'Bold', value: 'bold' }, { type: 'push', label: 'Italic', value: 'italic' }, { type: 'push', label: 'Underline', value: 'underline' }, { type: 'separator' }, { type: 'select', label: 'Arial', value: 'fontname', disabled: true, menu: [ { text: 'Arial', checked: true }, { text: 'Arial Black' }, { text: 'Comic Sans MS' }, { text: 'Courier New' }, { text: 'Lucida Console' }, { text: 'Tahoma' }, { text: 'Times New Roman' }, { text: 'Trebuchet MS' }, { text: 'Verdana' } ] }, { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true }, { type: 'separator' }, { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true }, { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true } ] } ] } }); myEditor.render();
var myEditor = new YAHOO.widget.Editor('msgpost', { height: '200px', width: '385px', dompath: false, animate: true, toolbar: { titlebar: 'My Editor', buttons: [ { group: 'textstyle', label: 'Font Style', buttons: [ { type: 'push', label: 'Bold', value: 'bold' }, { type: 'push', label: 'Italic', value: 'italic' }, { type: 'push', label: 'Underline', value: 'underline' }, { type: 'separator' }, { type: 'select', label: 'Arial', value: 'fontname', disabled: true, menu: [ { text: 'Arial', checked: true }, { text: 'Arial Black' }, { text: 'Comic Sans MS' }, { text: 'Courier New' }, { text: 'Lucida Console' }, { text: 'Tahoma' }, { text: 'Times New Roman' }, { text: 'Trebuchet MS' }, { text: 'Verdana' } ] }, { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true }, { type: 'separator' }, { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true }, { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true } ] } ] } }); myEditor.render();
The Editor's Toolbar supports 2 types of buttons: advanced
and basic
.
Note: To use the advanced
button type you will need to make sure you include the Menu and Button Controls.
The following are advanced button types:
<select>
element.The following are basic button types:
<select>
element.Example code for each of these button types is included in the toolbar section above. You can also see a few examples of using the different button types in the Editor's example section.
With the above code you would get an Editor that looked like this:
The Rich Text Editor and the Toolbar are both loaded with Custom Events to which you can subscribe as you customize the editor's behavior to suit the specific needs of your application.
Some of the more common Rich Text Editor events include the following; for a full list, including the arguments passed to each event, see the API documentation for Rich Text Editor:
SimpleEditor Events
toolbarLoaded
afterRender
editorContentLoaded
editorMouseUp
editorMouseDown
editorDoubleClick
editorKeyUp
editorKeyPress
editorKeyDown
beforeNodeChange
afterNodeChange
beforeExecCommand
afterExecCommand
EditorObj.toolbar.on()
)
toolbarExpanded
toolbarCollapsed
colorPickerClicked
cmdClick
(dynamic event)menucmdClick
(dynamic event)buttonClick
Editor Events
toolbarLoaded
afterRender
editorContentLoaded
beforeEditorMouseUp
editorMouseUp
beforeEditorMouseDown
editorMouseDown
beforeEditorClick
editorClick
beforeEditorDoubleClick
editorDoubleClick
beforeEditorKeyUp
editorKeyUp
beforeEditorKeyPress
editorKeyPress
beforeEditorKeyDown
editorKeyDown
beforeNodeChange
afterNodeChange
beforeExecCommand
afterExecCommand
beforeOpenWindow
afterOpenWindow
closeWindow
windowCMDOpen
(dynamic event)windowCMDClose
(dynamic event)windowRender
windowInsertImageRender
windowCreateLinkRender
EditorObj.toolbar.on()
)
toolbarExpanded
toolbarCollapsed
colorPickerClicked
cmdClick
(dynamic event)menucmdClick
(dynamic event)buttonClick
Dynamic Events are special CustomEvent's that are dynamically created based on the value of a button in the Toolbar.
For example, if you had a button called "bold" you will be able to listen for the "boldClick" event or if you had a button called "foo", you would be able to listen for the "fooClick" event.
These events are best described with the following code:
var myEditor = new YAHOO.widget.Editor('msgpost', { //Snippet from button config buttons: [ { type: 'push', label: 'Bold', value: 'bold' }, { type: 'push', label: 'My Button 1', value: 'mybutton1' }, { type: 'push', label: 'My Button 2', value: 'mybutton2' } ] }); myEditor.on('toolbarLoaded', function() { //Using the Dynamic Event cmdClick where cmd is the value of the button above this.toolbar.on('boldClick', function(o) { alert('Bold Button was clicked'); }); //Using the Dynamic Event cmdClick where cmd is the value of the button above this.toolbar.on('mybutton1Click', function(o) { alert('mybutton1 was clicked'); }); //Standard Custom Event fired for all button clicks this.toolbar.on('buttonClick', function(o) { switch(o.button.value) { case 'bold': //Bold Code Here break; case 'mybutton1': //My Button 1 Code Here break; case 'mybutton2': //My Button 2 Code Here break; } }); }, myEditor, true); myEditor.render();
var myEditor = new YAHOO.widget.Editor('msgpost', { //Snippet from button config buttons: [ { type: 'push', label: 'Bold', value: 'bold' }, { type: 'push', label: 'My Button 1', value: 'mybutton1' }, { type: 'push', label: 'My Button 2', value: 'mybutton2' } ] }); myEditor.on('toolbarLoaded', function() { //Using the Dynamic Event cmdClick where cmd is the value of the button above this.toolbar.on('boldClick', function(o) { alert('Bold Button was clicked'); }); //Using the Dynamic Event cmdClick where cmd is the value of the button above this.toolbar.on('mybutton1Click', function(o) { alert('mybutton1 was clicked'); }); //Standard Custom Event fired for all button clicks this.toolbar.on('buttonClick', function(o) { switch(o.button.value) { case 'bold': //Bold Code Here break; case 'mybutton1': //My Button 1 Code Here break; case 'mybutton2': //My Button 2 Code Here break; } }); }, myEditor, true); myEditor.render();
Please refer to the API documentation for a full list of Custom Events that are available for the Rich Text Editor.
The Rich Text Editor's toolbar has a flexible plugin architecture that allows you to customize the editor's behavior for the purposes of your own application.
The example below will add a new button to the default toolbar. When this custom button is clicked it will insert the following HTML: "<b>This is the text to insert.</b>
" But the button will only be enabled if the user has focused a <div>
, so this text will never be inserted into an element within the editor other than a <div>
.
//Start with the constructor for our RTE: var myEditor = new YAHOO.widget.Editor('msgpost', { height: '300px', width: '522px' }); //Use the toolbarLoaded Custom Event; when that event fires, //we will execute a function that adds or custom button: myEditor.on('toolbarLoaded', function() { //Simple button config var button = { type: 'push', label: 'My Button 3', value: 'mybutton3', disabled: false }; //Add the button to the toolbar; "this" //refers to myEditor, our RTE instance: this.toolbar.addButton(button); //Now listen for the new buttons click and do something with it. //Note that "mybutton3Click" is an event synthesized for us //automatically because that's the value we gave our button //above: this.toolbar.on('mybutton3Click', function(o) { this.execCommand('inserthtml', '<b>This is the text to insert.</b>'); }, myEditor, true); //Setup the button to be enabled, disabled or selected this.on('afterNodeChange', function(o) { //Get the selected element var el = this._getSelectedElement(); //Get the button we want to manipulate var button = this.toolbar.getButtonByValue('mybutton3'); if (el && el.tagName == 'div') { this.toolbar.enableButton(button); } }, this, true); }, myEditor, true); myEditor.render();
//Start with the constructor for our RTE: var myEditor = new YAHOO.widget.Editor('msgpost', { height: '300px', width: '522px' }); //Use the toolbarLoaded Custom Event; when that event fires, //we will execute a function that adds or custom button: myEditor.on('toolbarLoaded', function() { //Simple button config var button = { type: 'push', label: 'My Button 3', value: 'mybutton3', disabled: false }; //Add the button to the toolbar; "this" //refers to myEditor, our RTE instance: this.toolbar.addButton(button); //Now listen for the new buttons click and do something with it. //Note that "mybutton3Click" is an event synthesized for us //automatically because that's the value we gave our button //above: this.toolbar.on('mybutton3Click', function(o) { this.execCommand('inserthtml', '<b>This is the text to insert.</b>'); }, myEditor, true); //Setup the button to be enabled, disabled or selected this.on('afterNodeChange', function(o) { //Get the selected element var el = this._getSelectedElement(); //Get the button we want to manipulate var button = this.toolbar.getButtonByValue('mybutton3'); if (el && el.tagName == 'div') { this.toolbar.enableButton(button); } }, this, true); }, myEditor, true); myEditor.render();
The Rich Text Editor uses a method based approach for applying execCommand
commands on selected text/elements. For example, when you call myEditor.execCommand('forecolor', 'FF0000');
, the editor actually calls an internal method called cmd_forecolor
.
This method will then process the command and act on it. It will return an array telling the execCommand
method whether it should or should not execute the document.execCommand
method.
Below is an example of the cmd_forecolor
method.
cmd_forecolor: function(value) { var exec = true, el = this._getSelectedElement(); if (!this._isElement(el, 'body')) { Dom.setStyle(el, 'color', value); this._selectNode(el); exec = false; } else { this._createCurrentElement('span', { color: value }); this._selectNode(this.currentElement[0]); exec = false; } return [exec]; },
cmd_forecolor: function(value) { var exec = true, el = this._getSelectedElement(); if (!this._isElement(el, 'body')) { Dom.setStyle(el, 'color', value); this._selectNode(el); exec = false; } else { this._createCurrentElement('span', { color: value }); this._selectNode(this.currentElement[0]); exec = false; } return [exec]; },
Using this technique, you can add support for your own execCommands
, or change the way that the Editor handles them.
If you're intereseted in extending the Toolbar with custom buttons (see the Flickr and Calendar examples that do this), the following section contains important information.
The nodeChange
event is your way of knowing when an interesting moment occurs inside of the Editor. Keep in mind that the editing canvas itself (the place where the user is inputting rich text) is, under the hood, an HTML document loaded within an iframe
with designMode
turned on — which is to say it has a DOM full of nodes. When the user is typing, she is adding to a single DOM node. But when she mouses to a new location, selects new texts, or performs any other action that changes the cursor's current position in the DOM, the nodeChange
event fires to let you know that the user appears to be performing an interesting action. Common user actions that can fire nodeChange
include mousedown, mouseup, arrow keys and other keypress events.
When a nodeChange
event is fired off via an internal editor event (or by manually calling myEditor.nodeChange()
in your own script), all of the Toolbar's buttons need to update their status to reflect the new state of the user's editor. All of the buttons that ship with the Rich Text Editor fall into one of three groups:
The Toolbar goes through the following states in updating its buttons:
_disabled
array (that is, the list of buttons that should be disabled when there is no selected content in the editor) and..._alwaysDisabled
object._alwaysEnabled
object, it will deselect the button.For custom buttons that you add to the Editor, it is best practice to subscribe to the afterNodeChange
event and update your button's enabled/disabled state at that time. See the Calendar example for sample code that allows you to do this.
/* These are the overrides to manipulate to control the behavior of the toolbar */ _disabled: [ 'createlink', 'forecolor', 'backcolor', 'fontname', 'fontsize', 'superscript', 'subscript', 'removeformat', 'heading' ], _alwaysDisabled: { }, _alwaysEnabled: { hiddenelements: true }
/* These are the overrides to manipulate to control the behavior of the toolbar */ _disabled: [ 'createlink', 'forecolor', 'backcolor', 'fontname', 'fontsize', 'superscript', 'subscript', 'removeformat', 'heading' ], _alwaysDisabled: { }, _alwaysEnabled: { hiddenelements: true }
The Rich Text Editor includes two convenience methods used when showing and hiding the editor. The methods are show()
and hide()
.
These methods do not control the display properties of the editor. They are designed to plugin to an event given by the editor's parent container. See the Editor inside a TabView control example here for more information.
By setting the editor's container or a parent element of the editor to display none, the editor can become un-responsive. So using the show method will allow the editor to fix itself and start behaving again. On the other hand, you don't want the editor doing any processing when it is hidden. So calling the hide method will close all open editor windows and stop all background processes and timers.
A simple example of using the show and hide events on a Container Control
//panel in a reference to a Container Control (Panel/Overlay/Dialog) //myEditor is a reference to your Editor instance //Setup the show event panel.showEvent.subscribe(myEditor.show, myEditor, true); //Setup the hide event panel.hideEvent.subscribe(myEditor.hide, myEditor, true);
//panel in a reference to a Container Control (Panel/Overlay/Dialog) //myEditor is a reference to your Editor instance //Setup the show event panel.showEvent.subscribe(myEditor.show, myEditor, true); //Setup the hide event panel.hideEvent.subscribe(myEditor.hide, myEditor, true);
The Rich Text Editor comes with a default presentation or "skin," part of the "Sam Skin" visual treatment that accompanies most YUI controls. You can read more about the general approach to skinning YUI components in this in-depth article.
The CSS provided with the Rich Text Editor is comprised of core, functional CSS as well as the Sam Skin visual treatment.
To explore the CSS which controls the Rich Text Editor's presentation, please review the Rich Text Editor's Skinning Example wherein the full CSS for the control is displayed.
For your convenience we have provided the Rich Text Editor's sprite PSD file in a zip available here.
About this Section: YUI generally works well with mobile browsers that are based on A-Grade browser foundations. For example, Nokia's N-series phones, including the N95, use a browser based on Webkit — the same foundation shared by Apple's Safari browser, which is found on the iPhone. The fundamental challenges in developing for this emerging class of full, A-Grade-derived browsers on handheld devices are:
There are other considerations, many of them device/browser specific (for example, current versions of the iPhone's Safari browser do not support Flash). The goal of these sections on YUI User's Guides is to provide you some preliminary insights about how specific components perform on this emerging class of mobile devices. Although we have not done exhaustive testing, and although these browsers are revving quickly and present a moving target, our goal is to provide some early, provisional advice to help you get started as you contemplate how your YUI-based application will render in the mobile world.
More Information:
The YUI Rich Text Editor does not currently support the iPhone or the Nokia N95. Due to the interaction model (specifically, the inability to make a selection), the Editor will not function as expected. In our tests, it appears that the Apple and Nokia Webkit implementations don't event recognize the Editor as an editing field — meaning that these browsers are, at present, deliberately not supporting the use of an iframe in design mode.
The best way to get around this is to not render the Editor when you come across one of these browsers. Take a look at this example of browser detection in the Yahoo Global Object for ways of doing that.
The YUI Library and related topics are discussed on the on the YUILibrary.com forums.
Also be sure to check out YUIBlog for updates and articles about the YUI Library written by the library's developers.
The YUI Library's public bug tracking and feature request repositories are located on the YUILibrary.com site. Before filing new feature requests or bug reports, please review our reporting guidelines.
All YUI 2.x users should review the YUI 2.8.2 security bulletin, which discusses a vulnerability present in YUI 2.4.0-2.8.1.
Copyright © 2013 Yahoo! Inc. All rights reserved.