Rich Text Editor
WYSIWYG rich text editor with toolbar, formatting buttons, heading dropdown, source view, word counter, and sizes.
Basic Editor
This is a rich text editor with a toolbar for formatting text, adding lists, quotes, and links.
<div class="rich-text">
<div class="rich-text-toolbar">
<div class="rich-text-toolbar-group">
<button class="rich-text-btn rich-text-btn-active" type="button" title="Bold">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 4h8a4 4 0 014 4 4 4 0 01-4 4H6z"/><path d="M6 12h9a4 4 0 014 4 4 4 0 01-4 4H6z"/></svg>
</button>
<button class="rich-text-btn" type="button" title="Italic">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/></svg>
</button>
<button class="rich-text-btn" type="button" title="Underline">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 3v7a6 6 0 006 6 6 6 0 006-6V3"/><line x1="4" y1="21" x2="20" y2="21"/></svg>
</button>
</div>
<div class="rich-text-toolbar-divider"></div>
<div class="rich-text-toolbar-group">
<button class="rich-text-btn" type="button" title="Bullet List">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><circle cx="4" cy="6" r="1" fill="currentColor"/><circle cx="4" cy="12" r="1" fill="currentColor"/><circle cx="4" cy="18" r="1" fill="currentColor"/></svg>
</button>
<button class="rich-text-btn" type="button" title="Numbered List">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><text x="2" y="8" font-size="7" fill="currentColor" stroke="none" font-family="sans-serif">1</text><text x="2" y="14" font-size="7" fill="currentColor" stroke="none" font-family="sans-serif">2</text><text x="2" y="20" font-size="7" fill="currentColor" stroke="none" font-family="sans-serif">3</text></svg>
</button>
<button class="rich-text-btn" type="button" title="Quote">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M4.583 17.321C3.553 16.227 3 15 3 13.011c0-3.5 2.457-6.637 6.03-8.188l.893 1.378c-3.335 1.804-3.987 4.145-4.247 5.621.537-.278 1.24-.375 1.929-.311 1.804.167 3.226 1.648 3.226 3.489a3.5 3.5 0 01-3.5 3.5c-1.073 0-2.099-.49-2.748-1.179zm10 0C13.553 16.227 13 15 13 13.011c0-3.5 2.457-6.637 6.03-8.188l.893 1.378c-3.335 1.804-3.987 4.145-4.247 5.621.537-.278 1.24-.375 1.929-.311 1.804.167 3.226 1.648 3.226 3.489a3.5 3.5 0 01-3.5 3.5c-1.073 0-2.099-.49-2.748-1.179z"/></svg>
</button>
</div>
<div class="rich-text-toolbar-divider"></div>
<div class="rich-text-toolbar-group">
<button class="rich-text-btn" type="button" title="Link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71"/></svg>
</button>
</div>
</div>
<div class="rich-text-editor" contenteditable="true" data-placeholder="Start writing...">
<p>This is a <strong>rich text</strong> editor with a toolbar for formatting text, adding lists, quotes, and links.</p>
</div>
<div class="rich-text-footer">
<div class="rich-text-counter"><span>18 words</span><span>96 characters</span></div>
</div>
</div> Requires: ux.min.css
<div class="flex flex-col w-full overflow-hidden bg-base-100 border border-base-300 rounded-box focus-within:border-primary focus-within:ring-3 focus-within:ring-primary/15 transition-[border-color,box-shadow]">
<div class="flex flex-wrap items-center gap-1 px-4 py-2 min-h-[52px] bg-base-200 border-b border-base-300">
<div class="flex items-center gap-0.5">
<button class="flex items-center justify-center min-w-11 min-h-11 p-1 bg-primary/15 text-primary rounded-field border-none cursor-pointer" type="button"><svg xmlns="http://www.w3.org/2000/svg" class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 4h8a4 4 0 014 4 4 4 0 01-4 4H6z"/><path d="M6 12h9a4 4 0 014 4 4 4 0 01-4 4H6z"/></svg></button>
<button class="flex items-center justify-center min-w-11 min-h-11 p-1 rounded-field border-none cursor-pointer text-base-content/60 hover:bg-base-300 hover:text-base-content" type="button"><svg xmlns="http://www.w3.org/2000/svg" class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/></svg></button>
<button class="flex items-center justify-center min-w-11 min-h-11 p-1 rounded-field border-none cursor-pointer text-base-content/60 hover:bg-base-300 hover:text-base-content" type="button"><svg xmlns="http://www.w3.org/2000/svg" class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 3v7a6 6 0 006 6 6 6 0 006-6V3"/><line x1="4" y1="21" x2="20" y2="21"/></svg></button>
</div>
<div class="shrink-0 w-px h-6 mx-2 bg-base-300"></div>
<div class="flex items-center gap-0.5">
<button class="flex items-center justify-center min-w-11 min-h-11 p-1 rounded-field border-none cursor-pointer text-base-content/60 hover:bg-base-300 hover:text-base-content" type="button" title="Link"><svg xmlns="http://www.w3.org/2000/svg" class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71"/></svg></button>
</div>
</div>
<div class="flex-1 min-h-[200px] p-6 text-base leading-relaxed text-base-content outline-none overflow-y-auto" contenteditable="true">
<p>This is a <strong>rich text</strong> editor with a toolbar.</p>
</div>
<div class="flex justify-between items-center px-4 py-2 bg-base-200 border-t border-base-300 text-xs text-base-content/40">
<div class="flex gap-4"><span>18 words</span><span>96 characters</span></div>
</div>
</div> Requires: tw.min.css
// Execute formatting command:
// document.execCommand('bold');
// document.execCommand('italic');
// document.execCommand('insertUnorderedList');
// Toggle active state:
// btn.classList.toggle('rich-text-btn-active'); Heading Dropdown
A heading example
Paragraph text below the heading.
<div class="rich-text">
<div class="rich-text-toolbar">
<div class="rich-text-dropdown">
<button class="rich-text-btn rich-text-btn-dropdown" type="button">
Normal
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z" clip-rule="evenodd"/></svg>
</button>
<div class="rich-text-dropdown-menu rich-text-dropdown-menu-open">
<button class="rich-text-dropdown-item rich-text-dropdown-item-h1" type="button">Heading 1</button>
<button class="rich-text-dropdown-item rich-text-dropdown-item-h2" type="button">Heading 2</button>
<button class="rich-text-dropdown-item rich-text-dropdown-item-h3" type="button">Heading 3</button>
<button class="rich-text-dropdown-item" type="button">Normal</button>
</div>
</div>
<div class="rich-text-toolbar-divider"></div>
<div class="rich-text-toolbar-group">
<button class="rich-text-btn" type="button" title="Bold">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 4h8a4 4 0 014 4 4 4 0 01-4 4H6z"/><path d="M6 12h9a4 4 0 014 4 4 4 0 01-4 4H6z"/></svg>
</button>
<button class="rich-text-btn" type="button" title="Italic">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/></svg>
</button>
</div>
</div>
<div class="rich-text-editor" contenteditable="true" data-placeholder="Start writing...">
<h2>A heading example</h2>
<p>Paragraph text below the heading.</p>
</div>
</div> Requires: ux.min.css
<div class="flex flex-col w-full overflow-hidden bg-base-100 border border-base-300 rounded-box">
<div class="flex flex-wrap items-center gap-1 px-4 py-2 min-h-[52px] bg-base-200 border-b border-base-300">
<div class="relative">
<button class="flex items-center gap-1 px-2 min-h-11 text-sm font-medium rounded-field border-none cursor-pointer text-base-content/60 hover:bg-base-300 hover:text-base-content" type="button">Normal <svg xmlns="http://www.w3.org/2000/svg" class="size-3" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z" clip-rule="evenodd"/></svg></button>
<div class="absolute top-full left-0 z-50 mt-1 p-1 min-w-[150px] bg-base-100 border border-base-300 rounded-box shadow-lg">
<button class="block w-full text-left px-4 py-2 rounded-field hover:bg-base-200 text-2xl font-bold" type="button">Heading 1</button>
<button class="block w-full text-left px-4 py-2 rounded-field hover:bg-base-200 text-xl font-semibold" type="button">Heading 2</button>
<button class="block w-full text-left px-4 py-2 rounded-field hover:bg-base-200 text-lg font-semibold" type="button">Heading 3</button>
<button class="block w-full text-left px-4 py-2 rounded-field hover:bg-base-200" type="button">Normal</button>
</div>
</div>
<div class="shrink-0 w-px h-6 mx-2 bg-base-300"></div>
<div class="flex items-center gap-0.5">
<button class="flex items-center justify-center min-w-11 min-h-11 p-1 rounded-field border-none cursor-pointer text-base-content/60 hover:bg-base-300" type="button"><svg xmlns="http://www.w3.org/2000/svg" class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 4h8a4 4 0 014 4 4 4 0 01-4 4H6z"/><path d="M6 12h9a4 4 0 014 4 4 4 0 01-4 4H6z"/></svg></button>
<button class="flex items-center justify-center min-w-11 min-h-11 p-1 rounded-field border-none cursor-pointer text-base-content/60 hover:bg-base-300" type="button"><svg xmlns="http://www.w3.org/2000/svg" class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/></svg></button>
</div>
</div>
<div class="flex-1 min-h-[200px] p-6 text-base leading-relaxed text-base-content outline-none" contenteditable="true">
<h2 class="text-2xl font-semibold mb-4">A heading example</h2>
<p>Paragraph text below the heading.</p>
</div>
</div> Requires: tw.min.css
// Toggle dropdown:
// dropdownBtn.addEventListener('click', () => {
// menu.classList.toggle('rich-text-dropdown-menu-open');
// });
// Apply heading:
// document.execCommand('formatBlock', false, 'h2'); Sizes & States
This editor is disabled.
This content is read-only. The toolbar and footer are hidden.
<!-- Small -->
<div class="rich-text rich-text-sm mb-4">
<div class="rich-text-toolbar">
<div class="rich-text-toolbar-group">
<button class="rich-text-btn" type="button" title="Bold"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 4h8a4 4 0 014 4 4 4 0 01-4 4H6z"/><path d="M6 12h9a4 4 0 014 4 4 4 0 01-4 4H6z"/></svg></button>
<button class="rich-text-btn" type="button" title="Italic"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/></svg></button>
</div>
</div>
<div class="rich-text-editor" contenteditable="true" data-placeholder="Small editor..."></div>
</div>
<!-- Error state -->
<div class="rich-text rich-text-error mb-4">
<div class="rich-text-toolbar">
<div class="rich-text-toolbar-group">
<button class="rich-text-btn" type="button" title="Bold"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 4h8a4 4 0 014 4 4 4 0 01-4 4H6z"/><path d="M6 12h9a4 4 0 014 4 4 4 0 01-4 4H6z"/></svg></button>
</div>
</div>
<div class="rich-text-editor" contenteditable="true" data-placeholder="Required field..."></div>
</div>
<!-- Disabled state -->
<div class="rich-text rich-text-disabled mb-4">
<div class="rich-text-toolbar">
<div class="rich-text-toolbar-group">
<button class="rich-text-btn" type="button" disabled><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 4h8a4 4 0 014 4 4 4 0 01-4 4H6z"/><path d="M6 12h9a4 4 0 014 4 4 4 0 01-4 4H6z"/></svg></button>
</div>
</div>
<div class="rich-text-editor">
<p>This editor is disabled.</p>
</div>
</div>
<!-- Readonly -->
<div class="rich-text rich-text-readonly">
<div class="rich-text-editor">
<p>This content is <strong>read-only</strong>. The toolbar and footer are hidden.</p>
</div>
</div> Requires: ux.min.css
<!-- Small -->
<div class="flex flex-col w-full overflow-hidden bg-base-100 border border-base-300 rounded-box mb-4">
<div class="flex items-center gap-1 px-4 py-2 bg-base-200 border-b border-base-300">
<button class="flex items-center justify-center min-w-9 min-h-9 p-1 rounded-field border-none cursor-pointer text-base-content/60 hover:bg-base-300" type="button"><svg xmlns="http://www.w3.org/2000/svg" class="size-[18px]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 4h8a4 4 0 014 4 4 4 0 01-4 4H6z"/><path d="M6 12h9a4 4 0 014 4 4 4 0 01-4 4H6z"/></svg></button>
<button class="flex items-center justify-center min-w-9 min-h-9 p-1 rounded-field border-none cursor-pointer text-base-content/60 hover:bg-base-300" type="button"><svg xmlns="http://www.w3.org/2000/svg" class="size-[18px]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/></svg></button>
</div>
<div class="flex-1 min-h-[120px] p-4 text-sm leading-relaxed text-base-content outline-none" contenteditable="true"></div>
</div>
<!-- Error -->
<div class="flex flex-col w-full overflow-hidden bg-base-100 border border-error rounded-box mb-4 focus-within:ring-3 focus-within:ring-error/15">
<div class="flex items-center gap-1 px-4 py-2 bg-base-200 border-b border-base-300">
<button class="flex items-center justify-center min-w-11 min-h-11 p-1 rounded-field border-none cursor-pointer text-base-content/60 hover:bg-base-300" type="button"><svg xmlns="http://www.w3.org/2000/svg" class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 4h8a4 4 0 014 4 4 4 0 01-4 4H6z"/><path d="M6 12h9a4 4 0 014 4 4 4 0 01-4 4H6z"/></svg></button>
</div>
<div class="flex-1 min-h-[200px] p-6 text-base leading-relaxed text-base-content outline-none" contenteditable="true"></div>
</div>
<!-- Disabled -->
<div class="flex flex-col w-full overflow-hidden bg-base-100 border border-base-300 rounded-box opacity-60 pointer-events-none mb-4">
<div class="flex items-center gap-1 px-4 py-2 bg-base-200 border-b border-base-300">
<button class="flex items-center justify-center min-w-11 min-h-11 p-1 rounded-field border-none text-base-content/60 opacity-40" type="button" disabled><svg xmlns="http://www.w3.org/2000/svg" class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 4h8a4 4 0 014 4 4 4 0 01-4 4H6z"/><path d="M6 12h9a4 4 0 014 4 4 4 0 01-4 4H6z"/></svg></button>
</div>
<div class="flex-1 min-h-[200px] p-6 bg-base-200 text-base leading-relaxed text-base-content">
<p>This editor is disabled.</p>
</div>
</div>
<!-- Readonly -->
<div class="flex flex-col w-full overflow-hidden bg-base-100 border border-base-300 rounded-box">
<div class="flex-1 min-h-[200px] p-6 bg-base-200 text-base leading-relaxed text-base-content">
<p>This content is <strong>read-only</strong>. The toolbar and footer are hidden.</p>
</div>
</div> Requires: tw.min.css
// Toggle source view:
// editor.classList.toggle('rich-text-source-view');
// Word count:
// const words = editor.innerText.trim().split(/\s+/).length;
// const chars = editor.innerText.length; | Class | Description |
|---|---|
.rich-text | Container (flex column) |
.rich-text-toolbar | Toolbar with formatting buttons |
.rich-text-toolbar-group | Button group within toolbar |
.rich-text-toolbar-divider | Vertical divider between groups |
.rich-text-btn | Toolbar button (44px touch target) |
.rich-text-btn-active | Active/pressed toolbar button |
.rich-text-btn-dropdown | Dropdown trigger button |
.rich-text-dropdown | Dropdown wrapper (relative) |
.rich-text-dropdown-menu | Dropdown panel (hidden by default) |
.rich-text-dropdown-menu-open | Show dropdown |
.rich-text-dropdown-item | Dropdown option |
.rich-text-dropdown-item-h1/h2/h3 | Heading size preview |
.rich-text-editor | Editable content area (contenteditable) |
.rich-text-source | HTML source textarea (hidden by default) |
.rich-text-source-view | Toggle to show source, hide editor |
.rich-text-footer | Footer with counter |
.rich-text-counter | Word/character count |
.rich-text-sm | Small editor (120px min-height, smaller buttons) |
.rich-text-lg | Large editor (300px min-height) |
.rich-text-error | Error state (red border) |
.rich-text-disabled | Disabled state |
.rich-text-readonly | Read-only (hides toolbar + footer) |
.rich-text.glass | Glass morphism variant |
.md-content | Markdown / rich content display (read-only) |
Markdown Content Display
Use .md-content to render HTML generated from markdown with proper spacing and typography that follows the theme.
md-content
Setup Guide: Restaurant
Configure your Restaurant hub using the ERPlora AI Assistant.
Step 1 — Describe your business
Send this as your first message to the AI Assistant:
Hola! Tengo un restaurante. Necesito configurar todo el sistema.
The assistant will detect your business type and install the right modules.
Step 2 — Configure your menu
- Ask the assistant to create product categories
- Add your dishes with prices
- Set up table layout
Step 3 — Set up your team
- Create employee profiles
- Assign roles (waiter, chef, manager)
- Set PINs for clock-in
Use bold for emphasis and inline code for commands. Visit erplora.com for more.
<div class="md-content">
<h1>Setup Guide: Restaurant</h1>
<blockquote>
<p>Configure your Restaurant hub using the ERPlora AI Assistant.</p>
</blockquote>
<h2>Step 1 — Describe your business</h2>
<p>Send this as your first message to the AI Assistant:</p>
<pre><code>Hola! Tengo un restaurante. Necesito configurar todo el sistema.</code></pre>
<p>The assistant will detect your business type and install the right modules.</p>
<h2>Step 2 — Configure your menu</h2>
<ul>
<li>Ask the assistant to create product categories</li>
<li>Add your dishes with prices</li>
<li>Set up table layout</li>
</ul>
<h2>Step 3 — Set up your team</h2>
<ol>
<li>Create employee profiles</li>
<li>Assign roles (waiter, chef, manager)</li>
<li>Set PINs for clock-in</li>
</ol>
<p>Use <strong>bold</strong> for emphasis and <code>inline code</code> for commands. Visit <a href="#">erplora.com</a> for more.</p>
</div> Requires: ux.min.css
// No JavaScript required - pure CSS component