Hey everyone. Welcome to today’s tutorial. In today’s tutorial, we will learn how to create a rich text editor. To build this project, we need HTML, CSS and Javascript. This tutorial is best suited for javascript intermediates.
If you would like to try other projects to improve your javascript skills, check out this playlist here. It consists of 70+ javascript projects. The complexity of these projects varies from easy to advanced. Thus these projects are suitable for beginners as well as experts.
The project consists of a text field that the user can type. Above this text field, we have an options section. In the options section, there are a variety of buttons and dropdowns. The user can use these options to modify the text. These options include:
- Text Formatters – Bold, Italic, Underline, Strikethrough.
- List Options – Ordered List, Unordered list.
- Undo and Redo Button
- Add Link and Remove Link Button.
- Alignment Option Buttons – Align Left, Align Right, Align Center, and Justify.
- Headings Dropdown – H1 To H6
- Fonts Family Dropdown – 6 Different Fonts
- Font Size Dropdown – Sizes ranging from 1 to 7.
- Options to change text color and highlight color.
Video Tutorial:
If you prefer to learn by coding along to a video tutorial rather than reading this blog post, check out the video here down below. Also subscribe to my youtube channel where I post new tips, tricks and tutorials related to web development regularly.
Project Folder Structure:
Now before we move to the actual coding, let us take a look at the project folder structure. We create a project folder called – ‘Rich Text Editor’. Inside this folder, we have three files – index.html, style.css and script.js. These files are the HTML document, the stylesheet and the script file.
HTML:
We start with the HTML code. Firstly copy the code below and paste it into your HTML document. This creates the layout necessary for our project.
<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Rich Text Editor</title> <!-- FontAwesome Icons --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" /> <!-- Google Fonts --> <link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet" /> <!-- Stylesheet --> <link rel="stylesheet" href="style.css" /> </head> <body> <div class="container"> <div class="options"> <!-- Text Format --> <button id="bold" class="option-button format"> <i class="fa-solid fa-bold"></i> </button> <button id="italic" class="option-button format"> <i class="fa-solid fa-italic"></i> </button> <button id="underline" class="option-button format"> <i class="fa-solid fa-underline"></i> </button> <button id="strikethrough" class="option-button format"> <i class="fa-solid fa-strikethrough"></i> </button> <button id="superscript" class="option-button script"> <i class="fa-solid fa-superscript"></i> </button> <button id="subscript" class="option-button script"> <i class="fa-solid fa-subscript"></i> </button> <!-- List --> <button id="insertOrderedList" class="option-button"> <div class="fa-solid fa-list-ol"></div> </button> <button id="insertUnorderedList" class="option-button"> <i class="fa-solid fa-list"></i> </button> <!-- Undo/Redo --> <button id="undo" class="option-button"> <i class="fa-solid fa-rotate-left"></i> </button> <button id="redo" class="option-button"> <i class="fa-solid fa-rotate-right"></i> </button> <!-- Link --> <button id="createLink" class="adv-option-button"> <i class="fa fa-link"></i> </button> <button id="unlink" class="option-button"> <i class="fa fa-unlink"></i> </button> <!-- Alignment --> <button id="justifyLeft" class="option-button align"> <i class="fa-solid fa-align-left"></i> </button> <button id="justifyCenter" class="option-button align"> <i class="fa-solid fa-align-center"></i> </button> <button id="justifyRight" class="option-button align"> <i class="fa-solid fa-align-right"></i> </button> <button id="justifyFull" class="option-button align"> <i class="fa-solid fa-align-justify"></i> </button> <button id="indent" class="option-button spacing"> <i class="fa-solid fa-indent"></i> </button> <button id="outdent" class="option-button spacing"> <i class="fa-solid fa-outdent"></i> </button> <!-- Headings --> <select id="formatBlock" class="adv-option-button"> <option value="H1">H1</option> <option value="H2">H2</option> <option value="H3">H3</option> <option value="H4">H4</option> <option value="H5">H5</option> <option value="H6">H6</option> </select> <!-- Font --> <select id="fontName" class="adv-option-button"></select> <select id="fontSize" class="adv-option-button"></select> <!-- Color --> <div class="input-wrapper"> <input type="color" id="foreColor" class="adv-option-button" /> <label for="foreColor">Font Color</label> </div> <div class="input-wrapper"> <input type="color" id="backColor" class="adv-option-button" /> <label for="backColor">Highlight Color</label> </div> </div> <div id="text-input" contenteditable="true"></div> </div> <!--Script--> <script src="script.js"></script> </body> </html>
CSS:
Next, we style our project using CSS. Now copy the code provided to you below and paste it into your stylesheet.
* { padding: 0; margin: 0; box-sizing: border-box; } body { background-color: #338cf4; } .container { background-color: #ffffff; width: 90vmin; padding: 50px 30px; position: absolute; transform: translate(-50%, -50%); left: 50%; top: 50%; border-radius: 10px; box-shadow: 0 25px 50px rgba(7, 20, 35, 0.2); } .options { display: flex; flex-wrap: wrap; align-items: center; gap: 15px; } button { height: 28px; width: 28px; display: grid; place-items: center; border-radius: 3px; border: none; background-color: #ffffff; outline: none; color: #020929; } select { padding: 7px; border: 1px solid #020929; border-radius: 3px; } .options label, .options select { font-family: "Poppins", sans-serif; } .input-wrapper { display: flex; align-items: center; gap: 8px; } input[type="color"] { -webkit-appearance: none; -moz-appearance: none; appearance: none; background-color: transparent; width: 40px; height: 28px; border: none; cursor: pointer; } input[type="color"]::-webkit-color-swatch { border-radius: 15px; box-shadow: 0 0 0 2px #ffffff, 0 0 0 3px #020929; } input[type="color"]::-moz-color-swatch { border-radius: 15px; box-shadow: 0 0 0 2px #ffffff, 0 0 0 3px #020929; } #text-input { margin-top: 10px; border: 1px solid #dddddd; padding: 20px; height: 50vh; } .active { background-color: #e0e9ff; }
Javascript:
Finally, we implement the logic using javascript. For this copy the code below and paste it into your script file.
let optionsButtons = document.querySelectorAll(".option-button"); let advancedOptionButton = document.querySelectorAll(".adv-option-button"); let fontName = document.getElementById("fontName"); let fontSizeRef = document.getElementById("fontSize"); let writingArea = document.getElementById("text-input"); let linkButton = document.getElementById("createLink"); let alignButtons = document.querySelectorAll(".align"); let spacingButtons = document.querySelectorAll(".spacing"); let formatButtons = document.querySelectorAll(".format"); let scriptButtons = document.querySelectorAll(".script"); //List of fontlist let fontList = [ "Arial", "Verdana", "Times New Roman", "Garamond", "Georgia", "Courier New", "cursive", ]; //Initial Settings const initializer = () => { //function calls for highlighting buttons //No highlights for link, unlink,lists, undo,redo since they are one time operations highlighter(alignButtons, true); highlighter(spacingButtons, true); highlighter(formatButtons, false); highlighter(scriptButtons, true); //create options for font names fontList.map((value) => { let option = document.createElement("option"); option.value = value; option.innerHTML = value; fontName.appendChild(option); }); //fontSize allows only till 7 for (let i = 1; i <= 7; i++) { let option = document.createElement("option"); option.value = i; option.innerHTML = i; fontSizeRef.appendChild(option); } //default size fontSizeRef.value = 3; }; //main logic const modifyText = (command, defaultUi, value) => { //execCommand executes command on selected text document.execCommand(command, defaultUi, value); }; //For basic operations which don't need value parameter optionsButtons.forEach((button) => { button.addEventListener("click", () => { modifyText(button.id, false, null); }); }); //options that require value parameter (e.g colors, fonts) advancedOptionButton.forEach((button) => { button.addEventListener("change", () => { modifyText(button.id, false, button.value); }); }); //link linkButton.addEventListener("click", () => { let userLink = prompt("Enter a URL"); //if link has http then pass directly else add https if (/http/i.test(userLink)) { modifyText(linkButton.id, false, userLink); } else { userLink = "http://" + userLink; modifyText(linkButton.id, false, userLink); } }); //Highlight clicked button const highlighter = (className, needsRemoval) => { className.forEach((button) => { button.addEventListener("click", () => { //needsRemoval = true means only one button should be highlight and other would be normal if (needsRemoval) { let alreadyActive = false; //If currently clicked button is already active if (button.classList.contains("active")) { alreadyActive = true; } //Remove highlight from other buttons highlighterRemover(className); if (!alreadyActive) { //highlight clicked button button.classList.add("active"); } } else { //if other buttons can be highlighted button.classList.toggle("active"); } }); }); }; const highlighterRemover = (className) => { className.forEach((button) => { button.classList.remove("active"); }); }; window.onload = initializer();
That’s it for this tutorial. If you face any issues while creating this project you can download the source code by clicking on the download button below. Also, if you have any queries, suggestions or feedback drop them in the comments below.
Happy Coding.
Hii I’m just livivng this commemt beacuse your js file is not working properly please review it and update.
Like only few command are doing its job in this bold italic or underlines are there but rest of event are not doing well
Hi I need to add upload image /drag image to the editor how to do.?
i have modified the code to insert images inside. if you want the code here is my whatsapp number +234 814 822 2698
Thank you very much. I’ve been looking for this solution in libraries that I could customize for a long time, but they were very limiting. It is obvious that the best solution would be with pure javascript. The video on youtube helped a lot, I believe I now have a good starting point to do what I need to do.
if you are having problems with the color changing
Replace this block of code:
//options that require value parameter (e.g colors, fonts)
advancedOptionButton.forEach((button) => {
button.addEventListener(“change”, () => {
modifyText(button.id, false, button.value);
});
});
With the following code:
// Font color and highlight color
const foreColorInput = document.getElementById(“foreColor”);
const backColorInput = document.getElementById(“backColor”);
foreColorInput.addEventListener(“input”, () => {
modifyText(“foreColor”, false, foreColorInput.value);
});
backColorInput.addEventListener(“input”, () => {
modifyText(“backColor”, false, backColorInput.value);
});
// Other options that require value parameter (e.g., fonts)
advancedOptionButton.forEach((button) => {
if (button.id !== “foreColor” && button.id !== “backColor”) {
button.addEventListener(“change”, () => {
modifyText(button.id, false, button.value);
});
}
});
i add preview html in this code, you can see your text in html code now