---
title: "Markdown editor"
type: plugin
version: "2.1.2"
doc_version: "2.2.2"
status: stable
date: 2026-02-27
library: Frutjam
stack: tailwind_css
compatibility: universal
framework_agnostic: true
runtime_requirement: none
description: "Easy to embeddable JavaScript markdown editor with real-time preview, syntax highlighting, and easy integration for web projects"
url: https://frutjam.com/plugins/markdown-editor
---

# The Native-First, High-Performance Markdown Plugin for JavaScript

## 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


## 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 `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](https://github.com/cure53/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

# Markdown Editor

## 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

```bash
npm install markdown-text-editor
```


OR

#### Using a CDN

Alternatively, include the following CDN links in your HTML

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

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

```javascript
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      | Type             | Default      | Purpose                                                                                                                                                                                                                              |
| ------------- | ---------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `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.                                     |
| `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. |

#### 🛠 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**, and the document's **character count** — all updated in real time. It is visible by default and each stat can be toggled independently.

| Key     | Type      | Default | Description                     |
| ------- | --------- | ------- | ------------------------------- |
| `line`  | `boolean` | `true`  | Show the current line number.   |
| `col`   | `boolean` | `true`  | Show the current column number. |
| `chars` | `boolean` | `true`  | Show the total character count. |

##### Usage Examples

```javascript
// Default — all stats 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 } });
```


### 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
// 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.

```javascript
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. 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
<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 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
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
{
  "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.

#### Image Alt Text Validation (`altInput`)

To ensure your content remains accessible and SEO-friendly, `MarkdownEditor` enforces alt text validation by default. You can configure this behavior using either a boolean shorthand or a detailed object.

- **Default Behavior**: If `altInput` is not defined, it defaults to `{ required: true }`
- **Enforce Accessibility**: Users will be prevented from inserting an image until an alt description is provided


##### Configuration Examples:

###### 1. Default (No configuration needed)

```javascript
// Alt text is REQUIRED by default
image: {
  fileInput: { uploadUrl: '/api/upload' }
}
```


###### 2. Shorthand (Disable Validation)

If you want to allow images without descriptions, simply set the boolean to `false`.

```javascript
image: {
  altInput: false // Users can now skip the alt text field
}
```


###### 3. Object-based (Explicit)

```javascript
image: {
    altInput: {
        required: false // Disables alt text validation — users can skip the alt field
    }
}
```


#### Standard Image Usage (No `fileInput`):

If `fileInput` is not configured, the editor defaults to a simple URL-based modal. This is ideal if your users are mostly linking to external image hosts.

```javascript
const options = {
  toolbar: [
    'link',
    'image',
    'preview'
  ],
}
const editor = new MarkdownEditor('#markdown-editor', options);
```


##### 💡 Why use params?

In frameworks like Laravel or Django, you cannot upload files without a CSRF token. By adding `_token` to the `params` object, your request will pass through the backend's security middleware seamlessly, maintaining the "Zero Logic" philosophy for your server-side controllers.

### 🔀 Editing Modes

**MarkdownEditor** offers two distinct ways to write and format your content. You can toggle between a traditional syntax-focused view or a modern, visual-first experience.

#### Configuration

You can define the starting mode using the `mode` property during initialization.

- `plain` (**Default**): A clean, high-performance Markdown environment where syntax (like `**bold**` or `# heading`) is visible. Ideal for developers and Markdown purists
- `hybrid`: A WYSIWYG-inspired experience that renders formatting (Bold, Italics, Headings) in real-time as you type, while still maintaining the underlying Markdown structure.


##### Implementation:

```javascript
// 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'
});
```


##### Hybrid and Plain Mode Preview:

###### Hybrid Mode

Visual formatting is rendered in real-time while you type.

# Hybrid mode markdown editor
This will render visual styles immediately.

###### Plain Mode (Default)

Focuses on raw Markdown syntax for a lightweight experience.

# Plain mode markdown editor
This shows the raw **syntax**.

| Config                                                                                                                                                                                                 | Property / Tool                                                                                                                                                    | Description                                                                                                                                                                                                                |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Options object                                                                                                                                                                                         | `placeholder`                                                                                                                                                      | Sets the placeholder text for the textarea (optional, as you can also use the standard HTML textarea attribute)                                                                                                            |
|                                                                                                                                                                                                        | `mode: 'hybrid'`                                                                                                                                                   | Enables a WYSIWYG-inspired experience that renders formatting (bold, italic, headings) in real-time as you type                                                                                                            |
| `toolbar`: Determines which tools    appear in the toolbar and their order.                                                                                                                            | `heading`                                                                                                                                                          | Opens a dropdown to select heading level H1–H6                                                                                                                                                                             |
|                                                                                                                                                                                                        | `bold`                                                                                                                                                             | Enables bold text formatting.                                                                                                                                                                                              |
|                                                                                                                                                                                                        | `italic`                                                                                                                                                           | Enables italic text formatting.                                                                                                                                                                                            |
|                                                                                                                                                                                                        | `strikethrough`                                                                                                                                                    | Allows for text strikethrough.                                                                                                                                                                                             |
|                                                                                                                                                                                                        | `ol`                                                                                                                                                               | (Ordered List): Converts text into a numbered list format.                                                                                                                                                                 |
|                                                                                                                                                                                                        | `ul`                                                                                                                                                               | (Unordered List): Converts text into a bullet point list.                                                                                                                                                                  |
|                                                                                                                                                                                                        | `checklist`                                                                                                                                                        | Adds checkboxes to your text, making it great for tasks, to-do lists, or tracking completion status.                                                                                                                       |
|                                                                                                                                                                                                        | `blockquote`                                                                                                                                                       | Highlight quoted or emphasized text.                                                                                                                                                                                       |
|                                                                                                                                                                                                        | `code`                                                                                                                                                             | Wraps selected text in single backticks for inline code. Clicking again removes the backticks.                                                                                                                             |
|                                                                                                                                                                                                        | `codeblock`                                                                                                                                                        | Wraps selected text in a triple-backtick fenced code block. Clicking again removes the fences.                                                                                                                             |
|                                                                                                                                                                                                        | `hr`                                                                                                                                                               | Inserts a `---` horizontal rule at the cursor position on its own line.                                                                                                                                                    |
|                                                                                                                                                                                                        | `table`                                                                                                                                                            | Inserts a starter 2x3 markdown table template at the cursor position.                                                                                                                                                      |
|                                                                                                                                                                                                        | `image`                                                                                                                                                            | Allows you to insert images via markdown syntax.                                                                                                                                                                           |
|                                                                                                                                                                                                        | `link`                                                                                                                                                             | Lets you add hyperlinks to your text.                                                                                                                                                                                      |
|                                                                                                                                                                                                        | `undo`                                                                                                                                                             | To reverse the last changes.                                                                                                                                                                                               |
| `redo`                                                                                                                                                                                                 | To reapply the last undone changes.                                                                                                                                |
| `indent`                                                                                                                                                                                               | To increase the indentation level.                                                                                                                                 |
| `outdent`                                                                                                                                                                                              | To decrease the indentation level.                                                                                                                                 |
| `preview`                                                                                                                                                                                              | Toggles a fullscreen side-by-side preview. Checkboxes in the preview pane are clickable and update the markdown source instantly. Press Escape to exit fullscreen. |
| [**Advanced image upload feature**](#advanced-image-upload):    Enables configuring image uploads to     your own server and setting the image     path via an API. This improves performance and SEO. | `fileInput`                                                                                                                                                        | `accept`: Array of allowed image file types (e.g. `'webp'`, `'avif'`).   `uploadUrl`: Backend endpoint where the file is sent via `POST`.   `params`: Optional object for extra data (CSRF tokens, user IDs, folder names) |
|                                                                                                                                                                                                        | `altInput`                                                                                                                                                         | `required: false`: Disables alt-text input validation (default is true)                                                                                                                                                    |

### 🌙 Theming

**MarkdownEditor** automatically inherits its theme from the surrounding page — no configuration required. The editor reads `data-theme` from the nearest ancestor at initialisation, so it stays in sync with your site's theme out of the box.

#### How theme is resolved (priority order)

1. **`theme` option** — explicit override passed in the options object
2. **`data-theme` on the `<textarea>`** — set directly on the element
3. **`data-theme` on any ancestor** — e.g. `<html>`, `<body>`, or a wrapper `<div>`


#### Available themes

`'light'` (default), `'dark'`, `'snowberry'`, `'darkberry'`

##### Option 1 — inherit from `<html>` or any ancestor (zero config)

```html
<html data-theme="dark">
  ...
  <textarea id="markdown-editor"></textarea>
  <script>
    new MarkdownEditor('#markdown-editor'); // picks up dark automatically
  </script>
```


##### Option 2 — set `data-theme` directly on the `<textarea>`

```html
<textarea id="markdown-editor" data-theme="dark"></textarea>
<script>
  new MarkdownEditor('#markdown-editor');
</script>
```


##### Option 3 — explicit `theme` option (overrides everything)

```javascript
new MarkdownEditor('#markdown-editor', {
    theme: 'dark'
});
```


#### 🎨 Custom Theme via CSS Variables

You can fully customize the editor's look by overriding its CSS variables on the `.markdown-editor-wrapper` element or any `[data-theme]` selector. All colors use the [OKLCH color space](https://oklch.com) for perceptually uniform results.

| Variable             | Purpose                                | Light default           | Dark default            |
| -------------------- | -------------------------------------- | ----------------------- | ----------------------- |
| `--color-base`       | Editor background                      | `oklch(100% 0 0)`       | `oklch(10.9% 0 0)`      |
| `--color-on-base`    | Primary text color                     | `oklch(22% 0 0)`        | `oklch(98% 0 0)`        |
| `--color-primary`    | Primary accent (toolbar active, links) | `oklch(51.1% .262 277)` | `oklch(66.4% .184 286)` |
| `--color-on-primary` | Text on primary-colored surfaces       | `oklch(96.2% .018 272)` | `oklch(10% .01 270)`    |
| `--color-secondary`  | Secondary accent                       | `oklch(59.1% .293 323)` | `oklch(65% .18 220)`    |
| `--color-accent`     | Highlight accent (inline code, italic) | `oklch(54.1% .281 293)` | `oklch(75% .18 50)`     |
| `--color-neutral`    | Neutral surfaces (borders, dividers)   | `oklch(15% 0 0)`        | `oklch(85% 0 0)`        |
| `--color-error`      | Error state color                      | `oklch(57.7% .245 27)`  | `oklch(60% .22 30)`     |
| `--border-radius`    | Corner rounding of the editor frame    | `0.25rem`               | |

##### Custom theme example

Override any variable on `.markdown-editor-wrapper` after the editor initialises, or define a custom `[data-theme]` block in your stylesheet:

```css
/* 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' });
```


- **Real-time Preview:** See your markdown rendered instantly as you type.
- **Syntax Highlighting:** Enhanced readability with clear code and markdown formatting.
- **Easy Integration**: Seamlessly integrate into any web project with minimal setup.
- **Customizable Toolbar:** Dynamically configure and reorder toolbar options like bold, italic, and more.


## Features

## 🔌 Native Form Integration

Works exactly like a standard `<textarea>`. No complex APIs—just use the `value` or `name` attribute. It "just works" with standard HTML form submissions in PHP, Django, or Node.js.

## 🖼️ Advanced Image Upload

Configure native server uploads via API. Avoid heavy Base64 strings to ensure faster page loads and superior SEO by hosting images on your own CDN.

## 🔀 Hybrid & Plain Modes

Switch between a **Hybrid (WYSIWYG)** experience for visual editing or **Plain Markdown** mode for a traditional coding feel.

## 🚀 High Performance

A tiny **~116KB** bundle optimized for "Heavy Content." Handles massive documents and large files without any input lag or performance drop.

## 🌍 Built-in RTL Support

Native support for Right-to-Left languages like Arabic, Urdu, and Farsi. Perfect for building globally accessible applications.

## 🌙 Adaptive Theming

Includes automatic Dark Mode support. It syncs with your system settings or the **Frutjam UI** library for a seamless visual experience.

## 📝 Smart Editing

GitHub-style automatic list continuation for ordered lists, unordered lists, and checklists — press `Enter` and the editor continues the pattern. Checkboxes in the preview pane are clickable and sync back to the markdown source instantly.

## 📱 Fully Responsive

A fluid, mobile-first UI that adapts perfectly to desktops, tablets, and smartphones for editing on the go.

## 📦 Universal Support

Compatible with **ESM, UMD, CommonJS, and IIFE**. Works out of the box via CDN (`<script src>`), npm, or any bundler (Vite, webpack, Rollup) — no extra configuration needed.

## ♿ Accessible by Default

Full ARIA support built in — toolbar landmark, labelled preview region, screen-reader-friendly buttons, `aria-pressed` on the preview toggle, `aria-disabled` on inactive tools, and correct focus restoration when modals close.

## 🛡️ Zero CSS Conflicts

Editor styles are fully scoped to `.markdown-editor-wrapper`. Tailwind's global preflight is excluded so the editor lives safely alongside Bootstrap, Tailwind, or any other framework without breaking their styles.

## Full Configuration Example

Use this comprehensive example to initialize **MarkdownEditor** with all primary features, including custom toolbar ordering and advanced image upload handling.

```javascript
const editor = new MarkdownEditor('#markdown-editor', {
    mode: 'hybrid',
    placeholder: 'Start writing...',
    footer: {
        line: true,
        col: true,
        chars: true,
    },
    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'
    ],
});
```

