Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b571475
[add] document Markdown encoder support
serhiipylypchuk1991 May 21, 2026
5fb98f1
[add] document insertValue() method
serhiipylypchuk1991 May 22, 2026
4620b96
[add] document copy and paste behavior
serhiipylypchuk1991 May 22, 2026
a51b41b
[add] document inline base64 image insertion
serhiipylypchuk1991 May 22, 2026
ab426ba
[update] note paste and drag-and-drop as image upload sources
serhiipylypchuk1991 May 22, 2026
575a11d
[update] address review on copy and paste section
serhiipylypchuk1991 May 22, 2026
1c76f31
[update] tighten wording in imageUploadUrl change log
serhiipylypchuk1991 May 26, 2026
5940afb
[update] address review on insertValue docs
serhiipylypchuk1991 May 26, 2026
94d4605
[update] note nested-structure limits in Markdown
serhiipylypchuk1991 May 26, 2026
3d4da9d
[add] hide-suggest event docs
serhiipylypchuk1991 May 27, 2026
6eac577
[add] insert-token event docs
serhiipylypchuk1991 May 27, 2026
34f4c79
[add] show-suggest event docs
serhiipylypchuk1991 May 27, 2026
44b66d8
[add] triggers config docs
serhiipylypchuk1991 May 27, 2026
a49929b
[add] triggerTemplate config docs
serhiipylypchuk1991 May 27, 2026
d1adb47
[add] Mentions and tags guide
serhiipylypchuk1991 May 27, 2026
6948c9c
[update] add suggestion events to events overview
serhiipylypchuk1991 May 27, 2026
ce748b7
[update] add trigger configs to properties overview
serhiipylypchuk1991 May 27, 2026
90c074d
[update] mention triggers in configuration guide
serhiipylypchuk1991 May 27, 2026
d764692
[fix] correct anchor for custom toolbar controls link
serhiipylypchuk1991 May 27, 2026
f888bf7
[update] register trigger pages in sidebar
serhiipylypchuk1991 May 27, 2026
b77eef1
[update] document trigger action callback
serhiipylypchuk1991 Jun 3, 2026
2f2a6b7
[update] align insert-token handler in guide
serhiipylypchuk1991 Jun 3, 2026
5ae4c90
[update] address review on triggers docs
serhiipylypchuk1991 Jun 3, 2026
91c9d94
Merge pull request #43 from DHTMLX/sp-next-v-SVAR-2944
serhiipylypchuk1991 Jun 4, 2026
73f496d
Merge remote-tracking branch 'origin/sp-next-v-2-1' into sp-next-v-SV…
serhiipylypchuk1991 Jun 4, 2026
278e942
Merge pull request #42 from DHTMLX/sp-next-v-SVAR-2920
serhiipylypchuk1991 Jun 4, 2026
d50b295
Merge pull request #41 from DHTMLX/sp-next-v-SVAR-2763
serhiipylypchuk1991 Jun 4, 2026
eca3d4c
Merge pull request #40 from DHTMLX/sp-next-v-SVAR-2670
serhiipylypchuk1991 Jun 4, 2026
cf2c7f6
[fix] resolve index.md conflict with base, fix Markdown example
serhiipylypchuk1991 Jun 4, 2026
9077008
Merge branch 'sp-next-v-2-1' of https://github.com/DHTMLX/docs-richte…
serhiipylypchuk1991 Jun 4, 2026
202b3a1
Merge pull request #39 from DHTMLX/sp-next-v-SVAR-2919
serhiipylypchuk1991 Jun 4, 2026
3b6c7e1
Merge pull request #46 from DHTMLX/sp-next-v-SVAR-1033
serhiipylypchuk1991 Jun 5, 2026
6ef8836
[fix] correct typos and wording in v2.1 docs
serhiipylypchuk1991 Jun 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions docs/api/config/image-upload-url.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,19 @@ description: You can learn about the imageUploadUrl config in the documentation

### Description

@short: Optional. Specifies the URL which will be used for image upload
@short: Optional. Specifies the URL which will be used for image upload (from the toolbar, menubar, clipboard paste, or drag-and-drop)

When the property is set, RichText uploads each inserted image to the given endpoint and inserts the URL returned by the server.

When the property is omitted or set to a falsy value (`""`, `null`, `undefined`), RichText switches to **inline mode**: the image file is read on the client and embedded directly into the content as a base64 data URL — no server is required. Inline images larger than 1024×800 are proportionally downscaled to fit within these limits.

:::note
Inline (base64) images are not preserved by the built-in DOCX / PDF [export](api/events/export.md). If you rely on export, supply an `imageUploadUrl` so that images reference an external location.
:::

:::caution
Base64 encoding increases the encoded payload by roughly one third relative to the original file. A document with several large inline images grows accordingly, which affects the size of the value returned by [`getValue()`](api/methods/get-value.md), the memory footprint of the editor, and the cost of persisting or transferring the content. Prefer a server `imageUploadUrl` for documents that contain many or large images.
:::

### Usage

Expand All @@ -18,15 +30,26 @@ imageUploadUrl?: string;

### Example

Upload images to a server endpoint:

~~~jsx {3}
// initialize RichText
new richtext.Richtext("#root", {
imageUploadUrl: "some URL"
imageUploadUrl: "https://example.com/upload"
// other configuration properties
});
~~~

Insert images inline as base64 (no server required) — omit the property or pass an empty string:

~~~jsx {2}
new richtext.Richtext("#root", {
// imageUploadUrl is not set, images are inserted as base64 data URLs
// other configuration properties
});
~~~

**Change log:** The property was added in v2.0
**Change log:** The property was added in v2.0. Starting with v2.1, the property is optional: when omitted, images are inserted inline as base64 data URLs.

**Related articles:** [Configuration](guides/configuration.md)

Expand Down
68 changes: 68 additions & 0 deletions docs/api/config/trigger-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
sidebar_label: triggerTemplate
title: triggerTemplate Config
description: You can learn about the triggerTemplate config in the documentation of the DHTMLX JavaScript RichText library. Browse developer guides and API reference, try out code examples and live demos, and download a free 30-day evaluation version of DHTMLX RichText.
---

# triggerTemplate

### Description

@short: Optional. Customizes how RichText renders items in the suggestion dropdown opened by a [`triggers`](api/config/triggers.md) entry

By default, the dropdown shows each item's `label` as plain text. Use `triggerTemplate` to render richer rows — for example, an avatar plus a name and an email.

### Usage

~~~jsx {}
function triggerTemplate({ data, trigger }) {
return "HTML template of the suggestion item";
};
~~~

### Parameters

The callback function takes an object with the following parameters:

- `data` - the current suggestion item (`{ id, label, url }`, plus any custom fields you add to the trigger's `data` source)
- `trigger` - the trigger character that opened the dropdown (`"@"`, `"#"`, etc.)

:::tip
The dropdown default width is `160px`. If you need more space for your template, add the `.wx-editor` parent in front of the selector:

~~~css {}
.wx-editor .wx-suggest-anchor {
width: 220px;
}
~~~
:::

### Example

The following code snippet configures two triggers: `@` for mentions and `#` for tags. Use `triggerTemplate` to expand the `trigger` value to render each dropdown differently. For the `@` dropdown the template returns a custom HTML row with an avatar (`data.image`), a nickname (`data.label`), and a full name (`data.name`). For the `#` trigger the template uses the `label`:

~~~jsx {5-6,8-15}
const { template, Richtext } = richtext;

new Richtext("#root", {
triggers: [
{ trigger: "@", data: people },
{ trigger: "#", data: tags }
],
triggerTemplate: template(obj => {
if (obj.trigger === "@") {
return `<div class="user">
<img class="user-avatar" src="${obj.data.image}">
<div class="user-nickname">${obj.data.label}</div>
<div class="user-name">${obj.data.name}</div>
</div>`;
}
// other triggers (for example, "#") use the plain label
return obj.data.label;
})
});
~~~

**Change log:** The property was added in v2.1

**Related articles:** [Mentions and tags](guides/mentions_and_tags.md)
241 changes: 241 additions & 0 deletions docs/api/config/triggers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
---
sidebar_label: triggers
title: triggers Config
description: You can learn about the triggers config in the documentation of the DHTMLX JavaScript RichText library. Browse developer guides and API reference, try out code examples and live demos, and download a free 30-day evaluation version of DHTMLX RichText.
---

# triggers

### Description

@short: Optional. Defines dropdown triggers for inserting mentions, tags, and other tokens

When a user types a configured character (for example, `@` or `#`), RichText opens a dropdown with predefined items. When the user selects an item, RichText inserts it into the document as a non-editable token (`<a data-token="..." data-token-id="...">`).

### Usage

~~~jsx {}
triggers?: Array<{
trigger: string,
data: Array<{ id?: string; label?: string; url?: string }>
| ((query: string) =>
Array<{ id?: string; label?: string; url?: string }>
| Promise<Array<{ id?: string; label?: string; url?: string }>>),
showTrigger?: boolean,
action?: (item) => void
}>;
~~~

### Parameters

Each entry of the `triggers` array accepts the following fields:

- `trigger` - (required) the character that opens the suggestion dropdown (for example, `"@"`, `"#"`, `"/"`, `"$"`)
- `data` - (required) the data source for the dropdown; can be an array, a sync function, or an async function. See [Data source forms](#data-source-forms)
- `showTrigger` - (optional) when `true` (default), RichText keeps the trigger character in the inserted token (for example, `@Alice`); when `false`, RichText inserts only `label` (for example, `Alice`)
- `action` - (optional) a custom callback called when a user selects an item. When set, RichText removes the typed trigger text (the trigger character plus the query) and calls `action(item)` **instead of** inserting a token. The callback receives the picked item and can insert any content instead of the selected one. The `action` parameter takes priority over `showTrigger`, which has no effect when `action` is set. See [Custom action](#custom-action)

### Data source forms

* **Static array** — RichText filters the array automatically by matching the query against `label` (case-insensitive, `startsWith`):

~~~jsx {3-7}
new richtext.Richtext("#root", {
triggers: [{
trigger: "@",
data: [
{ id: "alice", label: "Alice" },
{ id: "bob", label: "Bob" }
]
}]
});
~~~

* **Sync function** — RichText calls your function with the current `query` string; you do the filtering and return the matching array:

~~~jsx {3-6}
new richtext.Richtext("#root", {
triggers: [{
trigger: "#",
data: query => tags.filter(t =>
t.label.toLowerCase().startsWith(query.toLowerCase())
)
}]
});
~~~

* **Async function** — RichText calls your function with the current `query` string; return a `Promise` that resolves to the matching array. Useful for server-side search:

~~~jsx {3-8}
new richtext.Richtext("#root", {
triggers: [{
trigger: "+",
data: async query => {
const res = await fetch(`/api/users?q=${encodeURIComponent(query)}`);
const users = await res.json();
return users.map(u => ({ id: String(u.id), label: u.name, url: u.website }));
}
}]
});
~~~

### Suggestion item fields

Each item in `data` (or each item returned by a function) has the following fields:

- `id` - (optional) unique identifier saved on the inserted token. If omitted, RichText generates an ID automatically
- `label` - (optional) the text shown in the dropdown and inserted into the document. Required only for the default rendering; with a custom [`triggerTemplate`](api/config/trigger-template.md) you can render items from other fields (for example, `template(({ data }) => data.id)`) and omit `label`
- `url` - (optional) URL associated with the item. RichText stores the URL as the inserted token's `href` attribute. `Ctrl+Click` on the token opens the link

An item may also include any number of custom fields beyond `id`, `label`, and `url` (for example, `code` for an emoji, or `image` and `name` for an avatar). These extra fields are passed through to the [`triggerTemplate`](api/config/trigger-template.md) callback and to the `action` callback.

### Rendered token

When a user selects an item in the dropdown, RichText inserts a non-editable token element into the document:

~~~html {}
<a data-token="@" data-token-id="alice" href="mailto:alice@example.com">@Alice</a>
~~~

- `@` (in `data-token="@"`) - the item's `trigger`
- `alice` (in `data-token-id="alice"`) - the item's `id`
- `mailto:alice@example.com` (in `href="mailto:alice@example.com"`) - the item's `url`
- `@Alice` - the combination of `trigger` and `label`; with `showTrigger: false` it would be just `Alice`

Use the `data-token` and `data-token-id` attributes to target tokens with CSS, for example, to highlight all mentions of a user:

~~~css {}
.wx-editor-content a[data-token="@"][data-token-id="alice"] {
background: #fb8500;
color: #fff;
}
~~~

### Custom action

By default, when a user picks an item, RichText inserts the item into the document as a token. Set the `action` parameter to run your code instead: RichText removes the typed trigger string (the trigger character and the query) and calls the `action(item)` callback with the picked item. No token is inserted, so you can decide what to add to the document (or run your custom code). The `action` parameter takes priority over `showTrigger`. When `action` is set, `showTrigger` is ignored.

#### Add emoji

A common use case is inserting an emoji from a `:` trigger, where each item contains a custom `code` field. Pair `action` with [`triggerTemplate`](api/config/trigger-template.md) so the dropdown shows the emoji itself instead of just its label:

~~~jsx {8,12}
const { template, Richtext } = richtext;

const editor = new Richtext("#root", {
triggers: [
{
trigger: ":",
data: emoji, // [{ id: "apple", label: "apple", code: "1F34E" }, ...]
action: item => editor.insertValue(`<span>${emojiFromCode(item.code)} </span>`)
}
],
// render the emoji itself (not just its label) in the dropdown
triggerTemplate: template(({ data }) => `${emojiFromCode(data.code)} ${data.label}`)
});

function emojiFromCode(code) {
return String.fromCodePoint(parseInt(code, 16));
}
~~~

#### Group emoji by categories

When the `data` parameter is a function, you are not limited to the built-in `label` matching. You can run your own filtering and keep category headers in the dropdown. Add header items that include a `label` field and do not include `code`. The `data` function first finds the emoji that match the query, then returns emoji together with the headers of the categories that still have matches:

~~~jsx {18-26,31-33,41}
const { template, Richtext } = richtext;

// header items carry no `code` field; emoji items include one
const emoji = [
{ id: "$smileys", label: "Smileys", category: 1 }, // category
{ id: "grinning", label: "grinning", code: "1F600", category: 1 },
{ id: "smile", label: "smile", code: "1F604", category: 1 },
{ id: "$animals", label: "Animals", category: 2 }, // category
{ id: "dog", label: "dog", code: "1F436", category: 2 },
{ id: "cat", label: "cat", code: "1F431", category: 2 }
];

const editor = new Richtext("#root", {
triggers: [
{
trigger: ":",
data: query => {
const matched = emoji.filter(item =>
item.code &&
item.label.toLowerCase().startsWith(query.toLowerCase().trim())
);
const categories = new Set(matched.map(item => item.category));
// keep matching emoji plus the headers of categories that still match
return emoji.filter(item =>
item.code ? matched.includes(item) : categories.has(item.category)
);
},
action: item => editor.insertValue(`<span>${emojiFromCode(item.code)} </span>`)
}
],
// render emoji rows normally and category headers in bold
triggerTemplate: template(({ data }) =>
data.code ? `${emojiFromCode(data.code)} ${data.label}` : `<b>${data.label}</b>`
)
});

function emojiFromCode(code) {
return String.fromCodePoint(parseInt(code, 16));
}

// headers have no `code` — ignore picks on them so they are never inserted
editor.api.intercept("insert-token", ({ data }) => !!data.code);
~~~

#### Add slash-style command menu

You can use `action` to build a slash-style command menu (like `/` in Notion or Slack). Store a command name in each item's `id`, its options in a custom `config` field, and let the callback run it with [`api.exec`](api/internal/exec.md):

~~~jsx {13}
// each item stores an api.exec action name in `id` and its parameters in `config`
const commands = [
{ id: "set-text-style", label: "Heading 1", config: { tag: "h1" } },
{ id: "insert-list", label: "Bulleted list", config: { type: "bulleted" } },
{ id: "insert-line", label: "Divider" } // no config → `|| {}` applies
];

const editor = new richtext.Richtext("#root", {
triggers: [
{
trigger: "/",
data: commands,
action: item => editor.api.exec(item.id, item.config || {})
}
]
});
~~~

### Example

The following example sets up two triggers: `@` for mentions (each item carries a `url` that becomes the token's `href`) and `#` for tags (label only):

~~~jsx {4,11}
new richtext.Richtext("#root", {
triggers: [
{
trigger: "@",
data: [
{ id: "alice", label: "Alice", url: "mailto:alice@example.com" },
{ id: "bob", label: "Bob", url: "mailto:bob@example.com" }
]
},
{
trigger: "#",
data: [
{ id: "css", label: "CSS" },
{ id: "html", label: "HTML" }
]
}
]
});
~~~

**Change log:** The property was added in v2.1

**Related articles:** [Mentions and tags](guides/mentions_and_tags.md)
Loading