Custom Rich Text Editor: How to Build One with HTML, CSS, and JavaScript

Tech Insights

Introduction

Creating a custom rich text editor using HTML, CSS, and JavaScript gives you full control over its features and design. While there are several third-party editors like Summernote or Quill, they may come with limitations, such as a lack of customization, unwanted bloat, or licensing restrictions.

By building your own editor, you can:

  • Add only the features you need (e.g., bold, italic, underline, color options).
  • Customize the look and feel to align with your application’s theme.
  • Implement unique features like code view and content preview easily.

In this tutorial, we’ll guide you step by step to create a custom editor with features like:

  • Bold, Italic, Underline, and Strikethrough text formatting.
  • Font selection and color picker.
  • Text alignment options (left, center, right, justify).
  • Insert links and images.
  • A code view mode to edit raw HTML.A Preview section to display rendered content.

By the end of this guide, you’ll have a fully functional editor similar to the one below:

Custom Rich Text Editor

Setting Up the HTML

The first step in building our custom editor is setting up the HTML structure. This includes:

  1. A toolbar – Contains buttons and options for formatting text (e.g., bold, italic, font selection, color picker).
  2. An editable content area – The main space where users type and format their content.
  3. Code view toggle – Allows users to edit the raw HTML content.
  4. A Preview section – Renders the formatted content dynamically for review.

Here’s the full HTML code for the editor:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Custom Editor</title>
    <link rel="stylesheet" href="editor.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
</head>
<body>
    <div>
        <!-- Toolbar -->
        <div>
            <button title="Bold" onclick="execCmd('bold')"><i></i></button>
            <button title="Italic" onclick="execCmd('italic')"><i></i></button>
            <button title="Underline" onclick="execCmd('underline')"><i></i></button>
            <button title="Strikethrough" onclick="execCmd('strikeThrough')"><i></i></button>
            <select title="Font" onchange="execCmd('fontName', this.value)">
                <option value="Arial">Arial</option>
                <option value="Courier">Courier</option>
                <option value="Times New Roman">Times New Roman</option>
                <option value="Georgia">Georgia</option>
            </select>
            <select title="Style" onchange="execCmd('formatBlock', this.value)">
                <option value="p">Normal</option>
                <option value="h1">Heading 1</option>
                <option value="h2">Heading 2</option>
            </select>
            <input type="color" title="Font Color" onchange="execCmd('foreColor', this.value)">
            <button title="Align Left" onclick="execCmd('justifyLeft')"><i></i></button>
            <button title="Align Center" onclick="execCmd('justifyCenter')"><i></i></button>
            <button title="Align Right" onclick="execCmd('justifyRight')"><i></i></button>
            <button title="Insert Link" onclick="execCmd('createLink', prompt('Enter URL:', 'http://'))">
                <i></i>
            </button>
            <button title="Insert Image" onclick="execCmd('insertImage', prompt('Enter image URL:', 'http://'))">
                <i></i>
            </button>
            <button title="Code View" onclick="toggleCodeView()"><i></i></button>
        </div>
        <!-- Editor Section -->
        <div>
            <div id="editor" contenteditable="true"></div>
            <textarea id="code-view" style="display:none;"></textarea>
        </div>
        <!-- Preview Button -->
        <button onclick="prepareContentForSave()">Preview</button>
    </div>
    <!-- Preview Section -->
    <div>
        <h2>Content Preview</h2>
        <div id="display-content"></div>
    </div>
    <!-- JavaScript File -->
    <script src="editor.js"></script>
</body>
</html>

Code Explanation

Toolbar:

  • The toolbar includes buttons for formatting text: bold, italic, underline, alignments, etc.
  • Each button uses the onclick attribute to call the execCmd() JavaScript function with the appropriate formatting command.
  • The font selector and color picker allow dynamic changes to fonts and text colors.

Example:

   <button title="Bold" onclick="execCmd('bold')"><i></i></button>
   <input type="color" title="Font Color" onchange="execCmd('foreColor', this.value)">

Editor Section:

  • The main content area is a div with the contenteditable="true" attribute, making it editable.
  • The textarea element is hidden by default and only displayed when switching to code view.

Example:

    <div id="editor" contenteditable="true"></div>
    <textarea id="code-view" style="display:none;"></textarea>

Preview Section:

Clicking the Preview button dynamically generates the content preview in a separate div using JavaScript.

Font Awesome Integration:

  • Icons for the toolbar are provided using Font Awesome.
  • Ensure you include the Font Awesome CDN in the <head> section.

Script:

The JavaScript file (editor.js) will handle all button actions and interactions.

Styling the Editor with CSS

The next step is to style our editor for a polished look. The following CSS rules are designed to:

  • Ensure the toolbar and editor layout are clean and user-friendly.
  • Add consistent padding, margins, and borders.
  • Style buttons and dropdowns for a modern appearance.

Here’s the CSS code for the editor:

body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
}
.editor-container {
    width: 80%;
    margin: 20px auto;
}
.toolbar {
    border: 1px solid #ccc;
    padding: 10px;
    background: #f1f1f1;
    display: flex;
    flex-wrap: wrap;
}
.editor-wrapper {
    border: 1px solid #ccc;
    min-height: 300px;
    padding: 10px;
    background: #fff;
    margin-bottom: 10px;
}
#editor {
    min-height: 300px;
    background: #fff;
    outline: none; /* Remove the default focus outline */
}
#code-view {
    width: 100%;
    height: 300px;
}
button {
    margin: 2px;
    background: none;
    border: none;
    cursor: pointer;
    font-size: 16px;
}
button i {
    pointer-events: none;
}
select, input[type="color"] {
    margin: 2px;
    font-size: 16px;
}
.display-container {
    width: 80%;
    margin: 20px auto;
    padding: 10px;
    border: 1px solid #ccc;
    background: #f9f9f9;
}
#display-content {
    border: 1px solid #ccc;
    padding: 10px;
    background: #fff;
}
/* Specific styles for the Preview button */
.preview-button {
    background-color: black;
    color: white;
    padding: 10px 20px;
    margin: 10px 0;
    border: none;
    cursor: pointer;
    font-size: 16px;
    border-radius: 5px;
    display: inline-block;
    width: auto;
}
.preview-button:hover {
    background-color: #333;
}

Code Explanation

Toolbar and Buttons:

  • The toolbar uses display: flex to align items and provide a modern layout.
  • Buttons are styled to remove borders and have hover effects for better interaction.

Editor and Code View:

  • The #editor div is set with contenteditable and styled for padding and background.
  • The #code-view textarea appears only in code view mode and has a consistent size with the editor.

Preview Section:

  • Styled to differentiate it from the editor and provide a clean content display area.

Adding Toolbar Functionality with JavaScript

Now that our HTML and CSS are ready, it’s time to make the editor functional using JavaScript. We’ll focus on implementing the following features:

  1. Formatting actions (e.g., bold, italic, underline).
  2. Font and color selection.
  3. Code view toggle.
  4. Generating a content preview

Here’s the JavaScript code for the editor:

// Function to execute commands
function execCmd(command, value = null) {
    document.execCommand(command, false, value);
}
// Toggle between code and WYSIWYG view
function toggleCodeView() {
    const editor = document.getElementById("editor");
    const codeView = document.getElementById("code-view");
    if (codeView.style.display === "none") {
        codeView.value = editor.innerHTML; // Populate code view with HTML
        editor.style.display = "none";
        codeView.style.display = "block";
    } else {
        editor.innerHTML = codeView.value; // Apply HTML back to editor
        editor.style.display = "block";
        codeView.style.display = "none";
    }
}
// Prepare content for preview
function prepareContentForSave() {
    const editorContent = document.getElementById("editor").innerHTML;
    const displayContent = document.getElementById("display-content");
    displayContent.innerHTML = editorContent; // Render editor content in preview
}

Code Explanation

execCmd(command, value):

  • Uses the document.execCommand method to apply formatting commands like bold, italic, and font changes.

Example usage:

     execCmd('bold'); // Apply bold formatting
     execCmd('foreColor', '#ff0000'); // Change font color to red

Code View Toggle:

  • Switches between WYSIWYG and raw HTML code views by toggling the display of the #editor and #code-view elements.
  • Updates the code view with the editor’s HTML and vice versa.

Content Preview: (This feature is optional and primarily for demonstration purposes.)

  • Dynamically renders the editor’s content into the preview section.
  • Helps users see the final formatted output.

Enhancements and Best Practices

To make the custom editor more robust and production-ready, consider the following enhancements:

Undo and Redo Functionality

  • Use document.execCommand('undo') and document.execCommand('redo') to enable undo/redo support.
  • Add toolbar buttons for these actions.

Keyboard Shortcuts

  • Implement keyboard shortcuts (e.g., Ctrl+B for bold, Ctrl+I for italic).
  • Use the keydown event to capture and handle key combinations.

Sanitizing User Input

  • Prevent potential XSS attacks by sanitizing the editor’s content before rendering or saving.
  • Use libraries like DOMPurify for this purpose.

Custom Plugins

  • Add plugins to extend functionality, such as inserting tables, emojis, or charts.
  • Define reusable commands and toolbar options.

Mobile Optimization

  • Ensure the editor is touch-friendly and responsive for mobile devices.
  • Use media queries to adjust toolbar and editor styles for smaller screens.

Accessibility

  • Add ARIA attributes to improve screen reader support.
  • Ensure all toolbar buttons are keyboard-navigable.

By implementing these practices, you can transform the demo editor into a production-grade tool suitable for real-world applications.

Final Integration

Now that we have all the building blocks, let’s integrate them into a single cohesive project:

Folder Structure

  • Organize your files like this:
folder structure

Link the Files

  • Ensure the <head> of index.html includes:
     <link rel="stylesheet" href="editor.css">
     <script src="editor.js" defer></script>

Test Your Editor

  • Open index.html in your browser.
  • Test every toolbar button and preview functionality.
  • Check for any errors by checking the browser console.

By following these steps, your custom editor should now be fully functional! For the complete source code, visit the GitHub repository: Custom Rich Text Editor GitHub Repository.

Leave a Reply

Your email address will not be published. Required fields are marked *