Menu

How to Create a Basic Text Editor In JavaScript: A Step by Step Tutorial

How to Create a Basic Text Editor In JavaScript: A Step by Step Tutorial

Creating a rich-text editor in JavaScript isn't as difficult as you may think it is and it can give you the much needed control over your code and applications as you won't have to rely on 3rd party implementations if you're looking to add any custom functionality.

So today I'll be going over the steps to make a very simple text-editor with the usual basic functionality, such as text/font styling and adding embedded links.

While the following post won't be using any incredibly advanced topics in JavaScript, a fundamental knowledge of the core concepts will help greatly. I always recommend the following book Web Design with HTML, CSS, JavaScript and jQuery for anybody that's relatively new to JavaScript and web development in general.

Creating the editor

Let's start off by creating the actual text editor where users will be typing the given text. For that, we'll be using a standard div tag, and we will be setting the contenteditable attribute to 'true'.

The contenteditable attribute turns any container into an editable text field with default styling set by the browser.

<div class="editor" contenteditable="true"> 
</div>

About contenteditable

The contenteditable global attribute does indeed turn certain elements, like divs and spans into focusable editable widgets in the browser. These elements can be tabbed through, much like other text input elements, and can have their focus set dynamically as well.

You can also modify the color of the caret that appears within the editable element by specifying the 'caret-color' CSS property.

Which with some very basic styling, a div with contenteditable set to true looks something like the following. This is a regular div element, however you can type text directly into it.

And the CSS styling looks like the following:

.editor
{
    border:solid 1px #ccc;
    padding: 20px;
    min-height:200px;
}

The content inside of the container can be retrieved how you would normally retrieve any content inside of a div element using the innerHTML property of the container or innerText if you're looking to grab just the plain text content.

Creating the toolbar

Next up, let's set up a basic toolbar with the usual text formatting features, such as bolding and italicizing text. I will be using Font Awesome for the icons, as they have all the necessary text editor icons and are very easy to implement.

<div class="sample-toolbar">
    <span class="fa fa-bold fa-fw" aria-hidden="true"></span>
    <span class="fa fa-italic fa-fw" aria-hidden="true"></span>
    <span class="fa fa-list fa-fw" aria-hidden="true"></span>
    <span class="fa fa-link fa-fw" aria-hidden="true"></span>
</div>

And again, with some very basic styling, we have something like the following.

And the styling is as follows.

.sample-toolbar
{
    border:solid 1px #ddd;
    background:#f4f4f4;
    padding: 5px;
    border-radius:3px;
}

.sample-toolbar > span
{
    cursor:pointer;
}

.sample-toolbar > span:hover
{
    text-decoration:underline;
}

The benefit of creating your own text-editor, is that you can essentially add any features that you wish and you can then expand on those features.

For now, we'll just handle these 4 basic functions of making text bold, italic, creating lists and adding a hyperlink to any selected group of text.

Formatting

JavaScript includes built-in functions to handle the formatting for us, all we have to do is to specify the current text selection and the type of formatting that we are looking to implement. And we can do that with the following helper function.

function format(command, value) {
    document.execCommand(command, false, value);
 }

The execCommand has the following signature, which we'll break down below.

bool = document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)

The execCommand function returns true if the command and value are valid arguments for the current browser. And false otherwise. The second argument determines whether the default user interface should be shown. However, note that this parameter is not implemented in Firefox.

Bold

Let's start with 'bolding' the selected text. With the built in functions it is as easy as calling the format function with the appropriate values.


<span class="fa fa-bold fa-fw" onclick="format('bold')"></span>
    

In this case, there is no associated 'value' to go with the 'bold' command, so we can leave the argument out. And the same approach is taken for making text italic.

Italic


<span class="fa fa-italic fa-fw" onclick="format('italic')"></span>
    

In order to have the formatting take effect, you must be highlighting some text and be inside of a contenteditable container. The browser is in charge of running the command against the right contenteditable container, since you can have many on a single page.

List

And the same thing once again is applicable to creating list items, with the command name of 'insertunorderedlist'.


<span class="fa fa-list fa-fw" onclick="format('insertunorderedlist')"></span>
    

Next up, let's include the ability to add hyperlinks to some selected text in the editor. This is one of my favorite uses, as I do it often when linking in my articles. There are 2 different ways to accomplish this, and we'll talk about both down below and when to use each.

Hyperlinks

 function setUrl() {
    let url = document.getElementById('txtUrl').value;
    let sText = document.getSelection();

    document.execCommand('insertHTML', false, '<a href="' + url + '" target="_blank">' + sText + '</a>');
        //format('createlink', url);
 }

The first method involves using the 'createlink' command, which takes a 'url' as a value. This is the short and simple way of creating a hyperlink on the selected text. However, if you need to add any extra attributes to the url, such as a class or a target attribute, then you will need to use an alternative method.

Which is where the 'insertHTML' command comes into play. The command replaces whatever content you are highlighting with the given value. In our case, we want to replace the currently selected text, with an anchor tag, our desired attributes, and the selected text itself.

You should end up with something like the following.

Here is some default text. Try entering a URL in the form input above, then select any text here and click on the link icon in the toolbar.

This is a very quick and easy implementation of a text-editor.

But there is much power in having your own custom editor that you can essentially do whatever you wish to do with. This blog runs off of a very custom editor that I spent a fair amount of time on, but that makes my writing much more efficient than I would otherwise be.

The full source is down below for your editing and tweaking pleasures. And if you would like to see any features added, just comment down below.

Full Source

    
<html>
<head>
	<style>
		.editor
        {
			border:solid 1px #ccc;
			padding: 20px;
			min-height:200px;
        }

        .sample-toolbar
        {
			border:solid 1px #ddd;
			background:#f4f4f4;
			padding: 5px;
			border-radius:3px;
        }

        .sample-toolbar > span
        {
			cursor:pointer;
		}

        .sample-toolbar > span:hover
        {
			text-decoration:underline;
		}
	</style>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
</head>

<body>
	<div class="sample-toolbar">
		<a href="javascript:void(0)" onclick="format('bold')"><span class="fa fa-bold fa-fw"></span></a>
		<a href="javascript:void(0)" onclick="format('italic')"><span class="fa fa-italic fa-fw"></span></a>
		<a href="javascript:void(0)" onclick="format('insertunorderedlist')"><span class="fa fa-list fa-fw"></span></a>
		<a href="javascript:void(0)" onclick="setUrl()"><span class="fa fa-link fa-fw"></span></a>
		<span><input id="txtFormatUrl" placeholder="url" class="form-control"></span>
</div>

<div class="editor" id="sampleeditor">
	</div>

	<script>
		window.addEventListener('load', function(){
			document.getElementById('sampleeditor').setAttribute('contenteditable', 'true');
			document.getElementById('sampleeditor2').setAttribute('contenteditable', 'true');
        });

		function format(command, value) {
			document.execCommand(command, false, value);
		}

		function setUrl() {
			var url = document.getElementById('txtFormatUrl').value;
			var sText = document.getSelection();
			document.execCommand('insertHTML', false, '<a href="' + url + '" target="_blank">' + sText + '</a>');
			document.getElementById('txtFormatUrl').value = '';
		}
	</script>
</body>
</html>
    

Fork on Codepen.io

Walter G. author of blog post
Walter Guevara is a Computer Scientist, software engineer, startup founder and previous mentor for a coding bootcamp. He has been creating software for the past 20 years.

Get the latest programming news directly in your inbox!

Have a question on this article?

You can leave me a question on this particular article (or any other really).

Ask a question

Community Comments

A
Alex
1/31/2020 11:52:24 AM
Simple and straight to the point! Many thanks!
thatsoftwaredude.com logo
Walter
1/31/2020 12:12:32 PM
Glad you found it helpful!
S
Samuel Saah
5/7/2020 6:40:48 AM
Amazing !!!
N
Namit Singh
5/9/2020 1:59:10 AM
Hello your tutorial was Awesome. Thanks But i have one problem can you please help me in my case all options are working except bold anyone ??
thatsoftwaredude.com logo
Walter
5/9/2020 6:29:09 PM
Many thanks for the comment Namit. Let me know which browser you are using and OS and I can test it out and check no problem ??
k
1/4/2021 8:44:53 AM
i have already make richtext editor but how to set richtext editor in admin panel
D
5/9/2020 7:46:29 PM
Great tutorial! I remember reading somewhere that different browsers handle "contenteditable" differently. Does this work well in terms of backwards browser compatibility and cross-browser compatibility?
thatsoftwaredude.com logo
Walter
5/9/2020 8:22:55 PM
Thanks for the kind words Daryl. The format function is stable in all modern browsers for sure. However it is true that contenteditable has some discrepencies on different browsers still. One of the main issues that I have stumbled on is the inconsistencies when working with embedded contenteditable elements and adding/removing them in the DOM. Still very powerful though and I actually use it highly in my custom text editors that I use to write these articles.
M
Mike
6/2/2020 5:18:59 PM
cool, this is just what I was looking for and can't wait to start playing with it!
thatsoftwaredude.com logo
Walter
6/3/2020 5:32:48 PM
Glad you found it helpful Mike! If you have any questions on other features and such feel free to let me know.
S
Shahriar
7/29/2020 12:59:01 PM
Perfect Tutorial! Thanks for sharing
A
Anh Quan
8/1/2020 8:06:33 AM
I just found a bug in the code, every time when I highlighted the text, choose the Bold, Italic or both then highlighted the same text, enter the URL to make the text a hyperlink text, click the chain button to insert and then all of the bold, italic option has been cleared. Can you please update the code?
M
8/8/2020 9:53:17 PM
Hi. I'm new in this field, as a result i don't know what should i do for submit. let me explain it. i have a form:POST to send data to the backend. and i use textarea instead of contenteditable. how can i send inserted data in contenteditable. should i use ajax or something like that.
G
Gerald Mbuthia
1/8/2021 10:13:36 PM
Hey, since you have a form, you can just use action="/route", and when the button is clicked it sends your data to the back end, make sure you have given your textarea a name attribute which will be used to handle the data in it. Check this project out i did the same however i used a templating language, ejs, but works the same with an api https://github.com/geraldombuthia/todo/blob/master/views/todo.ejs
A
Abhishek Anand
9/16/2020 1:26:39 AM
How can I retrieve data from this text editor and save the data as string in the Database?
D
12/21/2020 6:37:38 AM
Exactly what I required Thanks a lot Three more things should also be added Color Picker, Table and Font Change I am waiting for thanx again
S
Steve
12/21/2020 6:33:38 PM
I was trying to implement this in a slightly different way by using a span instead of an a but it didnt work. I could use button instead of a and not have to include href="javascript:void(0)". It has something to do with the way clicking on a span (or probably non input element) takes the focus off of the contenteditable element.
S
Serser
1/1/2021 4:07:15 AM
,, This feature is obsolete. Although it may still work in some browsers, its use is discouraged since it could be removed at any time. Try to avoid using it.,, - - https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
m
2/4/2021 4:02:46 PM
This has been so helpful, how I wish you could also add one that allows upload of images at the same time
thatsoftwaredude.com logo
Walter
2/16/2021 8:32:27 PM
That is currently in the works!
J
Jay Walt
2/24/2021 3:22:49 PM
Love the script ... almost exactly what i need. Thank You. I am wanting to add an image and save to a webpage like a news post. Any Idaea's to help me?
R
Ritesh Singh
3/13/2021 10:10:21 PM
This is a very simple way of doing it. Thank you for the blog. Although I have one question you specified that to get the edited content back use inner HTML, if the user presses enter then the inner HTML gives the actual tag and not the text. How to handle that?
thatsoftwaredude.com logo
Walter
3/18/2021 6:58:39 PM
You are very welcome. And that is a good observation. By default the contenteditable element does indeed introduce its own HTML when adding a newline. One way to handle that situation is to capture the 'enter' key event if (e.keyCode === 13) { And to use the contenteditable 'inserthtml' action to add your own breakpoints. Something like the following might work: document.execCommand('insertHTML', false, '

'); In that particular case, when you press on the enter key, the

tags would be inserted on the current element.
a
aboozar
4/17/2021 6:26:27 AM
in websit: "https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand" Document.execCommand() Deprecated This feature is no longer recommended. Though some browsers might still support it, it may have already been removed from the relevant web standards, may be in the process of being dropped, or may only be kept for compatibility purposes. Avoid using it, and update existing code if possible; see the compatibility table at the bottom of this page to guide your decision. Be aware that this feature may cease to work at any time.
Ad Unit

Current Poll

Total Votes:
Q:
Submit

Add a comment