The Native-First, High-Performance Markdown Plugin for JavaScript
Markdown text editor plugin that transforms a native textarea into a full editing suite. WYSIWYG and plain Markdown modes, live preview, RTL support, dark mode. Works with Django, HTMX, Laravel, React, and any stack.
The Philosophy: "Native-First"
Most editors break the standard web workflow. MarkdownEditor embraces it.
Because it sits directly on top of a <textarea>, you don't need to learn a new way to handle data.
- No Data Binding Needed: Works with
<form method="POST">out of the box - Standard Access: Use
document.getElementById('editor').valuejust like a normal input. - Backend Agnostic: Works with any backend (Python, Node.js, PHP, etc.) just like a normal form field
Key Features
🖼️ Advanced Image Upload (SEO Optimized)
Don't bloat your database with heavy Base64 strings. Configure our API to upload images directly to your server or S3 bucket. The editor receives the URL, keeping your Markdown files light and your site's SEO ranking high.
🔀 Hybrid & Plain Modes
Give your users the best of both worlds. Switch between a Visual (WYSIWYG) Hybrid mode for easy formatting and a Plain Markdown mode for distraction-free, raw syntax editing.
🌍 Global-Ready with RTL Support
Full native support for Right-to-Left (RTL) languages. Perfect for projects requiring Arabic, Urdu, or Farsi support with automatic text-direction alignment.
⚡ Performance at Scale
- Lightweight: A tiny ~116KB footprint that won't slow down your page load
- Large Document Support: Optimized to handle thousands of lines of text without input lag or browser freezing
- Smart Rendering: Debounced preview updates, cached style calculations, and conflict-free keyboard handling between list continuation and indentation — so Tab and Enter always do exactly one thing
♿ Accessible by Default
Full ARIA support is built in and requires no extra configuration. The toolbar is a proper role="toolbar" landmark, the preview pane is a labelled role="region", all SVG icons are hidden from screen readers, the preview toggle exposes its on/off state via aria-pressed, and disabled toolbar buttons use both disabled and aria-disabled so assistive technology is never misled. Modals return focus to the triggering button when closed.
🛡️ Zero CSS Conflicts
All editor styles are fully scoped to the .markdown-editor-wrapper element. Tailwind's global preflight (element resets for h1–h6, a, button, etc.) is excluded, so the editor can live alongside Bootstrap, Tailwind, or any other CSS framework on the same page without breaking a single style.
🔒 XSS Safe Preview
The rendered preview is sanitized via DOMPurify before being written to the DOM. Script tags, inline event handlers, and malicious URLs in crafted markdown input are stripped automatically — no configuration required.
Markdown Editor Demo
Quick Implementation
1. Installation
You can install it using NPM, import the JavaScript file directly, or use a CDN for rapid deployment.
Install via NPM
npm install markdown-text-editor |
Using a CDN
Alternatively, include the following CDN links in your HTML
<script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script> |
2. The HTML Structure
Simply place a <textarea> inside your standard form. No special wrappers required.
1 2 3 4 | <form action="/api/save" method="POST"> <textarea id="markdown-editor" name="content"># Hello World</textarea> <button type="submit">Save Content</button> </form> |
3. Import JS and CSS and initialise the plugin on your textarea element
1 2 3 4 5 6 | import MarkdownEditor from "markdown-text-editor"; const editor = new MarkdownEditor('#markdown-editor', { placeholder: 'Write your markdown...', toolbar: ['heading', 'bold', 'italic', 'strikethrough', 'ul', 'ol', 'checklist', 'blockquote', 'link', 'preview'], }); |
4. Configuration & Customization
You can fully customize the editor's behavior and interface by passing an options object. If you omit an option, the default value is used.
| Property | Kiểu | Mặc định | Mục đích |
|---|---|---|---|
mode |
string |
'plain' |
Sets the initial view. Use 'hybrid' for a WYSIWYG experience or 'plain' for raw syntax. |
placeholder |
string |
'Write...' |
Text shown when the editor is empty. |
toolbar |
array |
[...] |
Defines which tools appear and in what order. |
footer |
false | object |
all visible | Controls the status bar shown below the editor. Set to false to hide it entirely, or pass an object to toggle individual stats. |
theme |
string |
inherited | Explicitly sets the editor theme ('light', 'dark', 'snowberry', 'darkberry'). If omitted, the editor inherits data-theme from the nearest ancestor element or the <textarea> itself. |
minHeight |
number |
200 |
Minimum height in pixels the editor will shrink to when content is short. Pairs with maxHeight to set the auto-grow range. |
maxHeight |
number |
500 |
Maximum height in pixels the editor can grow to in non-fullscreen mode. Once content exceeds this height a scrollbar appears inside the editor. The editor also has a drag handle so users can manually resize it beyond this limit. |
onChange |
function |
undefined |
Callback fired on every content change — typing, toolbar actions, undo/redo, and list continuation. Receives the current markdown string as its only argument. |
🛠 Toolbar Customization
The toolbar is modular. You can create a minimal experience or a full-featured power suite by modifying the array.
Available Tools
| Category | Tool Keys |
|---|---|
| Typography | heading, bold, italic, strikethrough, blockquote |
| Lists | ul (bullet), ol (numbered), checklist |
| Code | code (inline), codeblock (fenced block) |
| Inserts | hr (horizontal rule), table (table template) |
| Media | link, image |
| Editing | undo, redo, indent, outdent |
| View | preview |
💡 Implementation Tips:
- Reordering: The buttons appear in the exact order you list them in the array
- Removing: Simply omit any key (like
image) from the array to disable that feature entirely for the user - Native Fallback: If you don't provide a
placeholderin JS, the plugin will automatically use theplaceholderattribute from your HTML<textarea>
📊 Footer (Status Bar)
The footer sits below the editor and shows the cursor's line, column, the document's character count, and optionally the word count — all updated in real time. It is visible by default and each stat can be toggled independently.
| Key | Kiểu | Mặc định | Sự miêu tả |
|---|---|---|---|
line |
boolean |
true |
Show the current line number. |
col |
boolean |
true |
Show the current column number. |
chars |
boolean |
true |
Show the total character count. |
words |
boolean |
false |
Show the total word count. Off by default — set to true to enable. |
Usage Examples
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // Default — line, col, and chars visible new MarkdownEditor('#editor'); // Disable the footer entirely new MarkdownEditor('#editor', { footer: false }); // Hide only character count new MarkdownEditor('#editor', { footer: { chars: false } }); // Hide line and column, keep character count new MarkdownEditor('#editor', { footer: { line: false, col: false } }); // Show only line number new MarkdownEditor('#editor', { footer: { col: false, chars: false } }); // Enable word count alongside the defaults new MarkdownEditor('#editor', { footer: { words: true } }); // Show word count only new MarkdownEditor('#editor', { footer: { line: false, col: false, chars: false, words: true } }); |
5. Getting, Setting, and Submitting Content
One of the core strengths of MarkdownEditor is that it keeps the underlying <textarea> perfectly synchronized. Whether you are using a modern JavaScript framework or a traditional backend like Django, PHP, or Laravel, the workflow remains simple and native.
1. The Native Way (Recommended)
Because the editor enhances a standard textarea, you can use familiar DOM methods. This is the fastest way to interact with your data without learning a new API.
1 2 3 4 5 | // Retrieve content via ID const markdown = document.getElementById('markdown-editor').value; // Set content via ID (The editor UI updates automatically) document.getElementById('markdown-editor').value = "# New Heading Content"; |
2. Using a Variable Reference
If you have a reference to the textarea element, you can use it directly — no library-specific API needed.
1 2 3 4 5 6 7 | const textarea = document.getElementById('markdown-editor'); // Retrieve content const markdown = textarea.value; // Set content (the editor UI reflects this immediately) textarea.value = "## Updated via JS"; |
3. Setting and reading content
The recommended way to set initial content is directly in the <textarea> HTML — this works naturally with every backend framework (Django, Laravel, Rails, PHP, etc.) and the editor renders it automatically on init.
1 2 | <!-- Recommended: set content server-side --> <textarea id="markdown-editor"># Hello World</textarea> |
To read or update content at runtime, use the native textarea value. Call editor.render() after an update to refresh the preview and hybrid layer.
1 2 3 4 5 6 7 8 | const textarea = document.getElementById('markdown-editor'); // Read const markdown = textarea.value; // Update at runtime textarea.value = '# New content'; editor.render(); |
4. Tearing down the editor — destroy()
Call editor.destroy() to remove the editor DOM wrapper and restore the original <textarea> to its position in the document. Useful in single-page applications when unmounting a view.
1 2 3 4 | const editor = new MarkdownEditor('#markdown-editor'); // Remove the editor and restore the plain textarea editor.destroy(); |
Reacting to changes with onChange
Pass an onChange callback to be notified on every content change. Receives the current markdown string.
1 2 3 4 5 | const editor = new MarkdownEditor('#markdown-editor', { onChange(value) { console.log('Content changed:', value.length, 'characters'); } }); |
Draft auto-save with localStorage
Use onChange to save a draft on every keystroke. Restore it by pre-filling the textarea before initialising the editor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | const DRAFT_KEY = 'my-page-draft'; // Restore saved draft before init (only if textarea starts empty) const textarea = document.getElementById('markdown-editor'); const saved = localStorage.getItem(DRAFT_KEY); if (saved && !textarea.value) textarea.value = saved; // Save on every change const editor = new MarkdownEditor('#markdown-editor', { onChange(value) { localStorage.setItem(DRAFT_KEY, value); } }); // Clear draft after successful form submission document.querySelector('form').addEventListener('submit', () => { localStorage.removeItem(DRAFT_KEY); }); |
4. Effortless Automatic Form Submission
Because MarkdownEditor is built directly on the native <textarea>, it is compatible with every backend framework (Django, Laravel, PHP, Ruby on Rails, etc.) right out of the box.
This is where the "Native-First" philosophy shines. You don't need to manually sync data before submitting a form. The browser treats the editor exactly like a standard input field.
1 2 3 4 5 6 7 8 9 10 11 12 | <form method="POST" action="/api/submit"> <textarea id="markdown-editor" name="content" class="h-48" rows="5"> # Initial Content </textarea> <button type="submit">Submit to Server</button> </form> <script> // Just initialize it. That's it. new MarkdownEditor('#markdown-editor'); </script> |
Note: MarkdownEditor plugin initialization mandatory
Just use a standard HTML <form>. The name attribute on the textarea is what your server will use to identify the content.
🚀 Why it's a Game-Changer for Backends
Since the editor preserves the native <textarea> behavior, your server handles the data as a standard string. There is zero extra logic required—no preventDefault() and no manual FormData construction.
💡 Why this is a "Killer Feature":
Most editors (like Quill, Editor.js, simpleMDE, easyMDE) save data in complex JSON structures. If a developer uses those, they have to rewrite their database schema and their rendering logic.
With MarkdownEditor, a developer can take an old website, replace a plain <textarea> with your editor, and the backend doesn't even know it changed. It just receives the same raw text it always did, but the user gets a 10x better experience.
| Framework / Language | How to access the Markdown content |
|---|---|
| PHP | $_POST['content'] |
| Django | request.POST.get('content') |
| Node.js (Express) | req.body.content |
| Laravel | $request->input('content') |
| Ruby on Rails | params[:content] |
Configuration Options
🖼️ Advanced image upload
Handling image uploads natively—rather than relying on slow, memory-heavy Base64 strings—is a significant win for both performance and SEO.
Configuration Options
The image tool supports a fileInput configuration to handle direct server uploads.
accept: Define an array of allowed image formats (e.g., 'webp', 'avif')uploadUrl: Specify the backend endpoint where theFileobject will be sent viaPOSTparams: Optional object to send additional data (like CSRF tokens, user IDs, or folder names) alongside the image file
Usage example (Full Config)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | const options = { placeholder: 'Start writing...', toolbar: [ 'link', { image: { fileInput: { accept: ['webp', 'avif'], // restrict the image upload format uploadUrl: '/api/upload', // Your upload endpoint params: { _token: 'your_csrf_token_here', // Essential for Laravel/Django folder: 'blog_posts' } }, // Supports boolean: true/false OR object: { required: true } altInput: { required: true } } }, 'preview' ], } const editor = new MarkdownEditor('#markdown-editor', options); |
📡 Server Integration Details
1. The Request
The editor sends a POST request as multipart/form-data. By default, it includes:
image_file: The actual file objectimage_alt: The alt text entered by the user- ...plus any custom data defined in the
paramsobject
2. The Required Response
To confirm a successful upload and insert the image into the editor, your server must return the following JSON structure:
1 2 3 4 | { "success": true, "image_path": "https://cdn.yourdomain.com/uploads/image.webp" } |
Note: Ensure you use the key image_path for the URL of the uploaded image.
Xác thực văn bản thay thế hình ảnh (altInput)
Để đảm bảo nội dung của bạn vẫn có thể truy cập được và thân thiện với SEO, MarkdownEditor thực thi xác thực văn bản thay thế theo mặc định. Bạn có thể định cấu hình hành vi này bằng cách sử dụng tốc ký boolean hoặc đối tượng chi tiết.
- Hành vi mặc định: Nếu
altInputkhông được xác định, nó sẽ mặc định là{ bắt buộc: true - Thực thi khả năng truy cập: Người dùng sẽ bị ngăn chèn hình ảnh cho đến khi mô tả thay thế được cung cấp
Ví dụ về cấu hình:
1. Mặc định (Không cần cấu hình)
1 2 3 4 | // Alt text is REQUIRED by default image: { fileInput: { uploadUrl: '/api/upload' } } |
2. Viết tắt (Tắt xác thực)
Nếu bạn muốn cho phép hình ảnh không có mô tả, chỉ cần đặt boolean thành false.
1 2 3 | image: { altInput: false // Users can now skip the alt text field } |
3. Dựa trên đối tượng (Rõ ràng)
1 2 3 4 5 | image: { altInput: { required: false // Disables alt text validation — users can skip the alt field } } |
Cách sử dụng hình ảnh tiêu chuẩn (Không có fileInput):
Nếu fileInput không được định cấu hình, trình chỉnh sửa sẽ mặc định sử dụng phương thức dựa trên URL đơn giản. Điều này lý tưởng nếu người dùng của bạn chủ yếu liên kết đến các máy chủ hình ảnh bên ngoài.
1 2 3 4 5 6 7 8 | const options = { toolbar: [ 'link', 'image', 'preview' ], } const editor = new MarkdownEditor('#markdown-editor', options); |
💡 Tại sao nên sử dụng thông số?
Trong các framework như Laravel hoặc Django, bạn không thể tải tệp lên mà không có mã thông báo CSRF. Bằng cách thêm _token vào đối tượng params, yêu cầu của bạn sẽ chuyển qua phần mềm trung gian bảo mật của chương trình phụ trợ một cách liền mạch, duy trì triết lý "Zero Logic" cho bộ điều khiển phía máy chủ của bạn.
🔀 Chế độ chỉnh sửa
MarkdownEditor cung cấp hai cách riêng biệt để viết và định dạng nội dung của bạn. Bạn có thể chuyển đổi giữa chế độ xem tập trung vào cú pháp truyền thống hoặc trải nghiệm hiện đại, ưu tiên hình ảnh.
Cấu hình
Bạn có thể xác định chế độ bắt đầu bằng thuộc tính mode trong quá trình khởi tạo.
plain(Mặc định): Môi trường Markdown rõ ràng, hiệu suất cao trong đó hiển thị cú pháp (như**bold**hoặc# tiêu đề). Lý tưởng cho các nhà phát triển và những người theo chủ nghĩa thuần túy Markdownkết hợp: Trải nghiệm lấy cảm hứng từ WYSIWYG giúp hiển thị định dạng (Đậm, Nghiêng, Tiêu đề) trong thời gian thực khi bạn nhập, trong khi vẫn duy trì cấu trúc Markdown cơ bản.
Thực hiện:
1 2 3 4 5 6 7 8 9 10 11 12 | // Default initialization (Plain Mode) new MarkdownEditor('#markdown-editor'); // Explicit Plain Mode new MarkdownEditor('#markdown-editor', { mode: 'plain' }); // Hybrid (Visual) Mode new MarkdownEditor('#markdown-editor', { mode: 'hybrid' }); |
Xem trước chế độ kết hợp và đơn giản:
Chế độ kết hợp
Định dạng trực quan được hiển thị theo thời gian thực trong khi bạn nhập.
Chế độ đơn giản (Mặc định)
Tập trung vào cú pháp Markdown thô để có trải nghiệm nhẹ nhàng.
| Cấu hình | Thuộc tính/Công cụ | Sự miêu tả |
|---|---|---|
| Đối tượng tùy chọn | placeholder |
Đặt văn bản giữ chỗ cho vùng văn bản (tùy chọn, vì bạn cũng có thể sử dụng thuộc tính vùng văn bản HTML tiêu chuẩn) |
mode: 'hybrid' |
Cho phép trải nghiệm lấy cảm hứng từ WYSIWYG hiển thị định dạng (in đậm, in nghiêng, tiêu đề) trong thời gian thực khi bạn nhập | |
thanh công cụ: Xác định công cụ nàoxuất hiện trên thanh công cụ và thứ tự của chúng. |
heading |
Mở menu thả xuống để chọn cấp tiêu đề H1–H6 |
bold |
Cho phép định dạng văn bản in đậm. | |
italic |
Cho phép định dạng văn bản in nghiêng. | |
strikethrough |
Cho phép gạch ngang văn bản. | |
ol |
(Danh sách có thứ tự): Chuyển văn bản sang dạng danh sách đánh số. | |
ul |
(Danh sách không có thứ tự): Chuyển văn bản thành danh sách dấu đầu dòng. | |
checklist |
Thêm các hộp kiểm vào văn bản của bạn, giúp nó trở nên tuyệt vời cho các nhiệm vụ, danh sách việc cần làm hoặc theo dõi trạng thái hoàn thành. | |
blockquote |
Đánh dấu văn bản được trích dẫn hoặc nhấn mạnh. | |
code |
Bao văn bản đã chọn bằng dấu backticks đơn cho mã nội tuyến. Nhấp lại sẽ loại bỏ dấu tích ngược. | |
codeblock |
Bao bọc văn bản đã chọn trong khối mã có hàng rào ba dấu ngược. Nhấp chuột một lần nữa sẽ loại bỏ hàng rào. | |
hr |
Chèn một quy tắc ngang --- vào vị trí con trỏ trên dòng riêng của nó. |
|
table |
Chèn mẫu bảng đánh dấu 2x3 ban đầu vào vị trí con trỏ. | |
image |
Cho phép bạn chèn hình ảnh thông qua cú pháp đánh dấu. | |
link |
Cho phép bạn thêm siêu liên kết vào văn bản của mình. | |
undo |
Để đảo ngược những thay đổi cuối cùng. | |
redo |
Để áp dụng lại những thay đổi được hoàn tác gần đây nhất. | |
indent |
Để tăng mức độ thụt lề. | |
outdent |
Để giảm mức độ thụt lề. | |
preview |
Chuyển đổi chế độ xem trước toàn màn hình cạnh nhau. Các hộp kiểm trong khung xem trước có thể nhấp vào được và cập nhật nguồn đánh dấu ngay lập tức. Nhấn Escape để thoát toàn màn hình. | |
| Tính năng tải hình ảnh nâng cao lên: Cho phép định cấu hình tải hình ảnh lên máy chủ của riêng bạn và đặt đường dẫn hình ảnh thông qua API. Điều này cải thiện hiệu suất và SEO. |
fileInput |
chấp nhận: Mảng loại tệp hình ảnh được phép (ví dụ: 'webp', 'avif').uploadUrl: Điểm cuối phụ trợ nơi tệp được gửi qua POST.params: Đối tượng tùy chọn cho dữ liệu bổ sung (mã thông báo CSRF, ID người dùng, tên thư mục)
|
altInput |
bắt buộc: false: Tắt xác thực nhập văn bản thay thế (mặc định là đúng) |
⌨️ Phím tắt
Các hành động định dạng phổ biến có thể được kích hoạt trực tiếp từ bàn phím mà không cần chạm vào thanh công cụ. Mỗi phím tắt cũng được hiển thị trong chú giải công cụ của nút thanh công cụ tương ứng.
| Phím tắt | Hoạt động |
|---|---|
Ctrl + B / ⌘ B |
Chuyển đổi Đậm |
Ctrl + I / ⌘ I |
Chuyển đổi nghiêng |
Ctrl + K / ⌘ K |
Chèn liên kết |
Ctrl + ` / ⌘ ` |
Chuyển đổi Mã nội tuyến |
Ctrl + Shift + S / ⌘ ⇧ S |
Chuyển đổi |
Ctrl + Z / ⌘ Z |
Hoàn tác |
Ctrl + Shift + Z / ⌘ ⇧ Z |
Làm lại |
Tab |
Thụt lề các dòng đã chọn |
Shift + Tab |
Nhô ra các dòng đã chọn |
Ctrl + F / ⌘ F |
Mở bảng Tìm kiếm |
Ctrl + H / ⌘ H |
Mở bảng Tìm & Thay thế |
Escape |
Đóng Tìm bảng điều khiển/Thoát xem trước toàn màn hình |
🔍 Tìm & amp; Thay thế
Bảng điều khiển tìm và thay thế tích hợp có sẵn bên trong trình chỉnh sửa — không cần tiện ích mở rộng trình duyệt hoặc công cụ riêng biệt.
- Nhấn
Ctrl + F(hoặc⌘ F) để mở bảng Tìm - Nhấn
Ctrl + H(hoặc⌘ H) để mở Tìm & Thay thế bảng điều khiển - Tìm kiếm không phân biệt chữ hoa chữ thường và hiển thị bộ đếm kết quả khớp trực tiếp (ví dụ: 3 trên 12)
- Điều hướng các kết quả khớp bằng các nút ▲ / ▼ hoặc
Enter/Shift + Enter - Thay thế thay thế kết quả được đánh dấu hiện tại; Thay thế tất cả thay thế mọi lần xuất hiện cùng một lúc
- Nhấn
Escapeđể đóng bảng và trả tiêu điểm về trình chỉnh sửa
Bảng điều khiển nổi ở góc trên bên phải của khu vực nội dung trình soạn thảo và không làm gián đoạn quá trình viết.
🌙 Chủ đề
MarkdownEditor tự động kế thừa chủ đề của nó từ trang xung quanh — không cần cấu hình. Trình chỉnh sửa đọc data-theme từ tổ tiên gần nhất khi khởi tạo, để nó luôn đồng bộ với chủ đề trang web của bạn ngay từ đầu.
Cách giải quyết chủ đề (thứ tự ưu tiên)
tùy chọn chủ đề— ghi đè rõ ràng được truyền trong đối tượng tùy chọndata-themetrên<textarea>— được đặt trực tiếp trên phần tửdata-themetrên bất kỳ tổ tiên nào — ví dụ:<html>,<body>hoặc trình bao bọc<div>
Chủ đề có sẵn
'light' (mặc định), 'dark', 'snowberry', 'darkberry'
Tùy chọn 1 — kế thừa từ <html> hoặc bất kỳ tổ tiên nào (cấu hình không)
1 2 3 4 5 6 | <html data-theme="dark"> ... <textarea id="markdown-editor"></textarea> <script> new MarkdownEditor('#markdown-editor'); // picks up dark automatically </script> |
Tùy chọn 2 — đặt data-theme trực tiếp trên <textarea>
1 2 3 4 | <textarea id="markdown-editor" data-theme="dark"></textarea> <script> new MarkdownEditor('#markdown-editor'); </script> |
Tùy chọn 3 — tùy chọn theme rõ ràng (ghi đè mọi thứ)
1 2 3 | new MarkdownEditor('#markdown-editor', { theme: 'dark' }); |
🎨 Chủ đề tùy chỉnh thông qua các biến CSS
Bạn hoàn toàn có thể tùy chỉnh giao diện của trình chỉnh sửa bằng cách ghi đè các biến CSS của nó trên phần tử .markdown-editor-wrapper hoặc bất kỳ bộ chọn [data-theme] nào. Tất cả các màu đều sử dụng không gian màu OKLCH để mang lại kết quả đồng nhất về mặt nhận thức.
| Biến | Mục đích | Ánh sáng mặc định | Mặc định tối |
|---|---|---|---|
--color-base |
Nền soạn thảo | oklch(100% 0 0) |
oklch(10.9% 0 0) |
--color-on-base |
Màu văn bản chính | oklch(22% 0 0) |
oklch(98% 0 0) |
--color-primary |
Giọng chính (thanh công cụ đang hoạt động, liên kết) | oklch(51.1% .262 277) |
oklch(66.4% .184 286) |
--color-on-primary |
Văn bản trên bề mặt màu cơ bản | oklch(96.2% .018 272) |
oklch(10% .01 270) |
--color-secondary |
Giọng phụ | oklch(59.1% .293 323) |
oklch(65% .18 220) |
--color-accent |
Đánh dấu trọng âm (mã nội tuyến, in nghiêng) | oklch(54.1% .281 293) |
oklch(75% .18 50) |
--color-neutral |
Bề mặt trung tính (viền, vách ngăn) | oklch(15% 0 0) |
oklch(85% 0 0) |
--color-error |
Màu trạng thái lỗi | oklch(57.7% .245 27) |
oklch(60% .22 30) |
--border-radius |
Làm tròn góc của khung soạn thảo | 0.25rem |
|
Ví dụ về chủ đề tùy chỉnh
Ghi đè bất kỳ biến nào trên .markdown-editor-wrapper sau khi trình soạn thảo khởi tạo hoặc xác định khối [data-theme] tùy chỉnh trong biểu định kiểu của bạn:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* Override individual variables */ .markdown-editor-wrapper { --color-primary: oklch(60% 0.2 30); /* orange accent */ --border-radius: 0.5rem; } /* Or define a full custom theme */ [data-theme="brand"] .markdown-editor-wrapper, .markdown-editor-wrapper[data-theme="brand"] { --color-base: oklch(15% 0.01 250); --color-on-base: oklch(95% 0 0); --color-primary: oklch(65% 0.22 145); /* green */ --color-on-primary: oklch(10% 0 0); --color-accent: oklch(75% 0.18 60); --color-neutral: oklch(80% 0 0); --border-radius: 0.75rem; } |
new MarkdownEditor('#markdown-editor', { theme: 'brand' }); |
- Xem trước theo thời gian thực: Xem phần đánh dấu của bạn được hiển thị ngay lập tức khi bạn nhập.
- Đánh dấu cú pháp: Khả năng đọc nâng cao với mã rõ ràng và định dạng đánh dấu.
- Tích hợp dễ dàng: Tích hợp liền mạch vào bất kỳ dự án web nào với thiết lập tối thiểu.
- Thanh công cụ có thể tùy chỉnh: Tự động định cấu hình và sắp xếp lại các tùy chọn thanh công cụ như in đậm, in nghiêng, v.v.
Đặc trưng
🔌 Tích hợp biểu mẫu gốc
Hoạt động chính xác như <textarea> tiêu chuẩn. Không có API phức tạp—chỉ cần sử dụng thuộc tính value hoặc name. Nó "chỉ hoạt động" với việc gửi biểu mẫu HTML tiêu chuẩn bằng PHP, Django hoặc Node.js.
🖼️ Tải lên hình ảnh nâng cao
Định cấu hình tải lên máy chủ gốc thông qua API. Tránh các chuỗi Base64 nặng để đảm bảo tải trang nhanh hơn và SEO vượt trội bằng cách lưu trữ hình ảnh trên CDN của riêng bạn.
🔀 Hybrid & Plain Modes
Chuyển đổi giữa trải nghiệm Kết hợp (WYSIWYG) để chỉnh sửa trực quan hoặc chế độ Đánh dấu đơn giản để có cảm giác viết mã truyền thống.
🚀 Hiệu suất cao
Gói ~116KB nhỏ được tối ưu hóa cho "Nội dung nặng". Xử lý các tài liệu lớn và các tệp lớn mà không có bất kỳ độ trễ đầu vào hoặc giảm hiệu suất nào.
🌍 Hỗ trợ RTL tích hợp
Hỗ trợ gốc cho các ngôn ngữ từ phải sang trái như tiếng Ả Rập, tiếng Urdu và tiếng Farsi. Hoàn hảo để xây dựng các ứng dụng có thể truy cập toàn cầu.
🌙 Chủ đề thích ứng
Bao gồm hỗ trợ Chế độ tối tự động. Nó đồng bộ hóa với cài đặt hệ thống của bạn hoặc thư viện Giao diện người dùng Frutjam để có trải nghiệm hình ảnh liền mạch.
📝 Chỉnh sửa thông minh
Tính năng tiếp tục danh sách tự động theo kiểu GitHub dành cho danh sách có thứ tự, danh sách không có thứ tự và danh sách kiểm tra — nhấn Enter và trình chỉnh sửa sẽ tiếp tục mẫu. Các hộp kiểm trong khung xem trước có thể nhấp vào được và đồng bộ hóa trở lại nguồn đánh dấu ngay lập tức.
📱 Hoàn toàn đáp ứng
Giao diện người dùng linh hoạt, ưu tiên thiết bị di động, thích ứng hoàn hảo với máy tính để bàn, máy tính bảng và điện thoại thông minh để chỉnh sửa khi đang di chuyển.
📦 Hỗ trợ toàn cầu
Tương thích với ESM, UMD, CommonJS và IIFE. Hoạt động ngay lập tức thông qua CDN (<script src>), npm hoặc bất kỳ gói nào (Vite, webpack, Rollup) — không cần cấu hình bổ sung.
♿ Accessible by Default
Hỗ trợ ARIA đầy đủ được tích hợp sẵn — mốc thanh công cụ, vùng xem trước được gắn nhãn, các nút thân thiện với trình đọc màn hình, aria-pressed trên nút chuyển đổi xem trước, đã tắt và aria-disabled trên các công cụ không hoạt động và khôi phục tiêu điểm chính xác khi các chế độ đóng.
🛡️ Zero CSS Conflicts
Các kiểu trình soạn thảo hoàn toàn nằm trong phạm vi .markdown-editor-wrapper. Tính năng kiểm tra trước toàn cầu của Tailwind bị loại trừ để trình soạn thảo hoạt động an toàn cùng với Bootstrap, Tailwind hoặc bất kỳ khung nào khác mà không phá vỡ phong cách của chúng.
⌨️ Phím tắt
Ctrl+B, Ctrl+I, Ctrl+K, Ctrl+`, Ctrl+Shift+S — các thao tác định dạng phổ biến mà không cần chạm vào chuột. Mỗi phím tắt được hiển thị trong chú giải công cụ của nút thanh công cụ.
🔍 Tìm & amp; Thay thế
Nhấn Ctrl+F để tìm hoặc Ctrl+H để mở find & thay thế. Tìm kiếm không phân biệt chữ hoa chữ thường với bộ đếm so khớp trực tiếp, điều hướng tiếp theo/trước, thay thế một lần và thay thế tất cả — mà không cần rời khỏi trình chỉnh sửa.
Ví dụ về cấu hình đầy đủ
Sử dụng ví dụ toàn diện này để khởi tạo MarkdownEditor với tất cả các tính năng chính, bao gồm sắp xếp thanh công cụ tùy chỉnh và xử lý tải lên hình ảnh nâng cao.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | const editor = new MarkdownEditor('#markdown-editor', { mode: 'hybrid', placeholder: 'Start writing...', footer: { line: true, col: true, chars: true, words: true, }, onChange(value) { console.log('Content updated:', value.length, 'characters'); }, toolbar: [ 'heading', 'bold', 'italic', 'strikethrough', 'blockquote', 'ul', 'ol', 'checklist', 'code', 'codeblock', 'hr', 'table', { image: { fileInput: { accept: ['webp', 'avif', 'png'], uploadUrl: '/api/upload' } } }, 'link', 'undo', 'redo', 'indent', 'outdent', 'preview' ], }); // Read content natively const markdown = document.getElementById('markdown-editor').value; // Update content programmatically (dispatch input to keep preview in sync) // const ta = document.getElementById('markdown-editor'); // ta.value = '# New content'; // ta.dispatchEvent(new Event('input', { bubbles: true })); // destroy() when the view unmounts (SPAs) // editor.destroy(); |