Chuyển đến nội dung chính

Plugin đánh dấu hiệu suất cao, đầu tiên dành cho JavaScript

Cập nhật lần cuối:

Plugin soạn thảo văn bản Markdown biến vùng văn bản gốc thành bộ chỉnh sửa đầy đủ - không cần đồng bộ hóa. WYSIWYG và các chế độ Markdown đơn giản, xem trước trực tiếp, tìm và thay thế, hỗ trợ RTL, chế độ tối. Hoạt động với Django, Laravel, Rails, Node.js, PHP và bất kỳ ngăn xếp nào.

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').value just like a normal input.
  • Backend Agnostic: Works with any backend (Python, Node.js, PHP, etc.) just like a normal form field

MarkdownEditor so với EasyMDE/SimpleMDE

Hầu hết các trình soạn thảo đánh dấu JavaScript — EasyMDE, SimpleMDE, trình soạn thảo dựa trên CodeMirror — thay thế <textarea> của bạn bằng một phần tử tùy chỉnh. Điều đó có nghĩa là việc gửi biểu mẫu bị gián đoạn, .value không trả về kết quả nào và bạn phải viết thêm mã chỉ để đọc lại nội dung. MarkdownEditor thì khác — nó nâng cao vùng văn bản hiện có của bạn và không bao giờ thay thế nó.

Feature MarkdownTrình chỉnh sửa EasyMDE / SimpleMDE
Vùng văn bản gốc được bảo tồn ❌ Đã thay thế
Việc gửi biểu mẫu hoạt động như hiện trạng ❌ Yêu cầu thêm JS
Nhận/đặt giá trị qua .value ❌ Cần có API tùy chỉnh
Chế độ kết hợp WYSIWYG
Tích hợp Tìm & Thay thế
RTL support
Tương thích CSP (không có JS nội tuyến)
Không có xung đột CSS
Chế độ tối / chủ đề Limited
Kích thước gói ~116KB ~300KB+

Tích hợp khung

MarkdownEditor bảo tồn <textarea> gốc nên nó tích hợp với mọi khung phụ trợ mà không cần bất kỳ mã bổ sung nào. Máy chủ của bạn nhận được nội dung đánh dấu chính xác như từ bất kỳ trường biểu mẫu tiêu chuẩn nào.

Django

Thêm class vào tiện ích vùng văn bản của bạn và khởi chạy trình chỉnh sửa — request.POST['content'] hoạt động mà không cần thực hiện thêm bước nào.

python
1
2
3
4
5
6
7
8
# forms.py
class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['content']
        widgets = {
            'content': forms.Textarea(attrs={'class': 'markdown-editor'}),
        }
javascript
1
2
new MarkdownEditor('.markdown-editor');
// request.POST['content'] contains the markdown on submit

Laravel

Sử dụng f.text_area với một lớp — $request->input('content') nhận được mức giảm giá trực tiếp.

html
1
2
<textarea name="content" class="markdown-editor">{{ old('content') }}</textarea>
<script>new MarkdownEditor('.markdown-editor');</script>

Ruby trên đường ray

Hoạt động ngay với form_withparams[:content] chứa phần đánh dấu. Đối với Turbo Drive, hãy sử dụng turbo:load thay vì DOMContentLoaded.

javascript
1
2
3
4
5
6
document.addEventListener('turbo:load', () => {
    document.querySelectorAll('.markdown-editor:not([data-mde-init])').forEach(el => {
        el.setAttribute('data-mde-init', 'true');
        new MarkdownEditor(el);
    });
});

Node.js / Express

req.body.content nhận được điểm giảm khi gửi biểu mẫu — không có bước đồng bộ hóa, không có trích xuất tùy chỉnh.

html
1
2
3
<textarea name="content" class="markdown-editor"></textarea>
<script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script>
<script>new MarkdownEditor('.markdown-editor');</script>

PHP

$_POST['content'] hoạt động chính xác như với bất kỳ vùng văn bản tiêu chuẩn nào — hãy thả nó vào và việc xử lý biểu mẫu hiện tại của bạn không cần thay đổi gì.

html
1
2
3
4
5
6
<form method="POST" action="save.php">
  <textarea name="content" class="markdown-editor"></textarea>
  <button type="submit">Save</button>
</form>
<script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script>
<script>new MarkdownEditor('.markdown-editor');</script>

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
  • Kết xuất thông minh: Bản cập nhật xem trước đã được công bố, tính toán kiểu được lưu trong bộ nhớ đệm và xử lý bàn phím không xung đột giữa việc tiếp tục và thụt lề danh sách — vì vậy Tab và Enter luôn thực hiện chính xác một việc

♿ 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

Tất cả các kiểu trình chỉnh sửa đều nằm trong phạm vi hoàn toàn của phần tử .markdown-editor-wrapper. Tính năng kiểm tra trước toàn cầu của Tailwind (đặt lại thành phần cho h1h6, a, button, v.v.) bị loại trừ, do đó, trình chỉnh sửa có thể hoạt động cùng với Bootstrap, Tailwind hoặc bất kỳ khung CSS nào khác trên cùng một trang mà không phá vỡ một kiểu nào.

🔒 XSS Safe Preview

Bản xem trước được hiển thị sẽ được lọc qua DOMPurify trước khi được ghi vào DOM. Thẻ tập lệnh, trình xử lý sự kiện nội tuyến và URL độc hại trong đầu vào đánh dấu thủ công sẽ tự động bị loại bỏ — không cần cấu hình.

Markdown Editor Demo

Quick Implementation

1. Installation

NPM (các gói: Vite, webpack, Rollup, v.v.)

bash
npm install markdown-text-editor
javascript
1
2
import MarkdownEditor from 'markdown-text-editor';
new MarkdownEditor('#markdown-editor');

CDN: mô-đun ES

html
1
2
3
4
<script type="module">
  import MarkdownEditor from 'https://cdn.jsdelivr.net/npm/markdown-text-editor/dist/markdown-text-editor.es.js';
  new MarkdownEditor('#markdown-editor');
</script>

CDN: thẻ tập lệnh toàn cầu (IIFE)

Không cần nhập - MarkdownEditor tự động có sẵn dưới dạng biến toàn cục.

html
1
2
3
4
5
6
7
8
9
<form action="/api/save" method="POST">
  <textarea id="markdown-editor" name="content"># Hello World</textarea>
  <button type="submit">Save Content</button>
</form>

<script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script>
<script>
  new MarkdownEditor('#markdown-editor');
</script>

2. Cấu hình & Khởi tạo

Truyền một đối tượng tùy chọn để tùy chỉnh trình chỉnh sửa. Tất cả các tùy chọn đều là tùy chọn — bỏ qua bất kỳ tùy chọn nào để sử dụng giá trị mặc định.

javascript
1
2
3
4
const editor = new MarkdownEditor('#markdown-editor', {
  placeholder: 'Write your markdown...',
  toolbar: ['heading', 'bold', 'italic', 'strikethrough', 'ul', 'ol', 'checklist', 'blockquote', 'link', 'preview'],
});

Bạn thích Trình chỉnh sửa Markdown?

Phải mất 2 giây và giúp dự án phát triển. Nó là một phần của Frutjam, một thư viện thành phần CSS Tailwind miễn phí — một ngôi sao ở đó cũng hữu ích.

Sao trên GitHub

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' Đặt chế độ xem ban đầu. Sử dụng kết hợp để có trải nghiệm WYSIWYG hoặc đơn giản cho cú pháp thô.
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 Đặt rõ ràng chủ đề của trình soạn thảo (sáng, tối, dâu tuyết, dâu đen). Nếu bị bỏ qua, trình chỉnh sửa sẽ kế thừa data-theme từ phần tử tổ tiên gần nhất hoặc chính <textarea>.
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 Lệnh gọi lại được thực hiện khi có bất kỳ thay đổi nội dung nào — gõ, thao tác trên thanh công cụ, hoàn tác/làm lại và tiếp tục danh sách. Nhận chuỗi đánh dấu hiện tại làm đối số duy nhất của nó.

🛠 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 placeholder in JS, the plugin will automatically use the placeholder attribute 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 Hiển thị tổng số từ. Tắt theo mặc định — đặt thành true để bật.
Usage Examples
javascript
 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.

javascript
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

Nếu bạn có một tham chiếu đến phần tử vùng văn bản, bạn có thể sử dụng nó trực tiếp - không cần API dành riêng cho thư viện.

javascript
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

Cách được đề xuất để đặt nội dung ban đầu là trực tiếp trong HTML <textarea> - cách này hoạt động tự nhiên với mọi khung phụ trợ (Django, Laravel, Rails, PHP, v.v.) và trình chỉnh sửa tự động hiển thị nội dung đó trên init.

html
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.

javascript
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. Xé trình soạn thảo — 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.

javascript
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.

javascript
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.

javascript
 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.

html
 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

Vì trình chỉnh sửa giữ nguyên hành vi <textarea> gốc nên máy chủ của bạn xử lý dữ liệu dưới dạng chuỗi tiêu chuẩn. Không cần thêm logic nào—không có preventDefault() và không có cấu trúc FormData thủ công.

💡 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

Xử lý nguyên bản việc tải lên hình ảnh—thay vì dựa vào các chuỗi Base64 chậm và tốn nhiều bộ nhớ—là một thắng lợi đáng kể cho cả hiệu suất và 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 the File object will be sent via POST
  • params: Optional object to send additional data (like CSRF tokens, user IDs, or folder names) alongside the image file

Usage example (Full Config)

javascript
 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 object
  • image_alt: The alt text entered by the user
  • ...plus any custom data defined in the params object
2. The Required Response

To confirm a successful upload and insert the image into the editor, your server must return the following JSON structure:

json
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 altInput khô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)
javascript
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.

javascript
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)
javascript
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.

javascript
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 Markdown
  • kế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:
javascript
 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ào
xuấ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 nội tuyến
Ctrl + Shift + S  /  ⌘ ⇧ S Chuyển đổi Gạch ngang
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 & 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, do đó, nó luôn đồng bộ hóa với chủ đề trang web của bạn ngay từ đầu.

Cách giải quyết chủ đề (thứ tự ưu tiên)

  1. theme option — ghi đè rõ ràng được truyền trong đối tượng tùy chọn
  2. data-theme trên <textarea> - được đặt trực tiếp trên phần tử
  3. data-theme trê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)
html
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>
html
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ứ)
javascript
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:

css
 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;
}
javascript
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

Tiếp tục danh sách tự động theo kiểu GitHub 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 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-ép trên nút chuyển đổi xem trước, disabledaria-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 & Thay thế

Nhấn Ctrl+F để tìm hoặc Ctrl+H để mở tìm & 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.

javascript
 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();