omar-text-editor
v1.0.0
Published
A from-scratch, MIT-licensed rich text (WYSIWYG) editor — no build step required, works in plain HTML, any JS project, or Laravel Livewire.
Maintainers
Readme
Omar Text Editor
A from-scratch, MIT-licensed rich text (WYSIWYG) editor for the web. No license gate, no telemetry, no cloud dependency, no third-party code inside it — an original implementation you can drop into any plain HTML page, any JS/TS project, or a Laravel/Livewire app.
Author: Md Omar Faruk ([email protected])

Features
- Text formatting — bold, italic, underline, strikethrough, super/subscript, inline code, text & background color, font family/size, line height
- Headings, blockquote, horizontal rule, bulleted/numbered lists (nested)
- Alignment, indent/outdent, per-side (top/right/bottom/left) block spacing
- Links & named anchors, with autolink
- Images — insert by URL/upload/drag-drop/paste, drag-resize, align
- Media — YouTube, Vimeo, Google Maps, Google Slides/Docs/Sheets, Spotify,
CodePen embeds, plus self-hosted video/audio (
<video>/<audio>); align, drag-resize, full width - Generic embed — paste a raw "Share → Embed" snippet from any supported provider, sanitized against a strict host allowlist (never arbitrary iframe/script injection)
- Tables — insert, row/column/cell operations, drag-resize (column, row, or the whole table), multi-cell selection, move
- Code samples with syntax highlighting
- Emoji picker, special character picker
- Find & replace, live word/character count
- A TinyMCE-style breadcrumb (element path) in the status bar
- Undo/redo history, a full keyboard shortcut set
- Optional File/Edit/View/Insert/Format/Tools/Table menu bar
- First-run onboarding tour
- A pluggable architecture — every feature above is a self-contained plugin; write your own the same way (see docs/PLUGINS.md)
Quick start
Plain HTML — no build step
Clone (or download the ZIP)
this repo — the built files already live in dist/, no build step
required — and drop them into any page:
git clone https://github.com/wholeomarfaruk/rich-text-editor.git<link rel="stylesheet" href="dist/theme/default.css" />
<link rel="stylesheet" href="dist/theme/content.css" />
<textarea id="editor">Hello <strong>world</strong>!</textarea>
<script src="dist/omar-text-editor.min.js"></script>
<script>
const editor = OmarTextEditor.init({
selector: '#editor',
plugins: ['link', 'image', 'table', 'searchreplace', 'wordcount'],
toolbar: 'undo redo | blockformat | bold italic underline | bullist numlist | link image table | removeformat',
});
</script>That's it — no server, no build tooling, no account/API key required.
npm / ES modules
npm install omar-text-editorimport { init } from 'omar-text-editor';
import 'omar-text-editor/dist/theme/default.css';
import 'omar-text-editor/dist/theme/content.css';
const editor = init({
selector: '#editor',
plugins: ['link', 'image', 'table'],
toolbar: 'undo redo | bold italic underline | link image table',
});Works with any bundler (Vite, webpack, esbuild, Rollup) — it's a plain
TypeScript source tree with a UMD/ESM build and full .d.ts types, no
framework dependency.
Laravel + Livewire
Livewire re-renders and morphs its component's DOM on every server
round-trip, which will fight a naively-mounted editor unless you protect
it with wire:ignore. Full copy-paste setup — a ready-made Blade
component, the Alpine lifecycle glue, wire:model wiring, and a
troubleshooting table — is in docs/LIVEWIRE.md.
Build from source
npm install
npm run build # outputs dist/omar-text-editor.{js,esm.js,min.js}, dist/*.d.ts, dist/theme/*.css
npm run watch # rebuild on change
npm run typecheck # tsc --noEmit
npm test # vitest runTry it
After npm run build, open any of:
examples/basic.html— full feature set, every plugin loaded, menu bar onexamples/preview-test.html— a form + live rendered previewexamples/custom-toolbar.html— a minimal hand-picked toolbar, no pluginsexamples/headless.html— no built-in toolbar at all, driven entirely by an external UI callingeditor.execCommand(...)
Docs
- docs/API.md — full public API reference (options, methods, events, commands, plugin list, toolbar config syntax)
- docs/LIVEWIRE.md — Laravel Livewire integration guide
- docs/PLUGINS.md — how to write a custom plugin
- docs/SHORTCUTS.md — keyboard shortcut reference
- docs/PLAN.md and docs/phases/ — original build plan and phase-by-phase history
- CHANGELOG.md
Security
HTML is sanitized against an explicit allowlist (src/core/Schema.ts) on
every paste and setContent() call — disallowed tags/attributes are
stripped, javascript:/data:/vbscript: URLs are blocked, iframes are
only ever accepted from a fixed list of known embeddable hosts. This is
covered by a dedicated adversarial test suite
(test/xss-hardening.test.ts). That said, this is a client-side
control: always validate/sanitize rich-text input again server-side
before storing or rendering it back, the same as you would for any
user-supplied HTML.
License
MIT — see LICENSE. Free for personal and commercial use, no attribution required (though appreciated).
Contributing
Issues and pull requests are welcome. Run npm run typecheck && npm test
before submitting — the project has no linter beyond the TypeScript
compiler, so type errors and test failures are the bar.
