• Jodit
  • PRO
  • Builder
  • Getting Started
  • Playground
  • Examples
  • Documentation
  • Download
  • Overview
  • Issue tracker
  • Docs
  • Plugins
  • Demo
  • Pricing
  • File Browser Pro
  • Sign in
Get connected wth us on social networks!

Footer

Jodit Core

  • Jodit Home page
  • Documentation
  • Playground
  • Examples
  • Github
  • Issues

Integration

  • Jodit React
  • Jodit Angular
  • Jodit Vue
  • Jodit Yii2
  • Jodit Joomla

PRO/OEM plugins

  • AutoComplete
  • Backup Plugin
  • Button Generator
  • Change case
  • Custom Color Picker
  • Emoji
  • Finder
  • Google Search
  • Paste code
  • Show Blocks
  • Virtual Keyboard
  • Tune block
  • Highlight signature
  • Google Maps Editor
  • Export in PDF
  • Page Break
  • Iframe Editor
  • Paste from Word PRO
  • Mobile View
  • ToDo List
  • Translate

Links

  • Demo PRO/OEM
  • Demo FileBrowser PRO
  • Price
  • License
  • Support
  • For resellers

Versions

  • site v.0.1.844
  • Jodit PRO v.4.6.21
  • Jodit v.4.6.13
  • All versions
2025 © Copyright: XDSoft.net <support@xdsoft.net>
  • Getting started

    • Installation
    • Usage
    • Support
    • FAQs
    • Cloud
    • Examples
  • How to

    • Create plugin
    • Add custom button
    • Add custom font in the font list
    • How to create module
    • How to generate license key
    • How to make a backend finder
    • How to set up document view
  • Modes

    • Source mode
  • Customisation

    • Theme
    • Keyboard
  • API

    • License Rest API
    • JS API
    • Cloud Version
  • Changelog

  • Plugins

    • AutoComplete
    • Backup Plugin
    • Button Generator
    • Change case
    • Custom Color Picker
    • Emoji
    • Finder
    • Google Search
    • Paste code
    • Show Blocks
    • Virtual Keyboard
    • Tune block
    • Highlight signature
    • Google Maps Editor
    • Export in PDF
    • Page Break
    • Iframe Editor
    • Paste from Word PRO
    • Mobile View
    • ToDo List
    • Translate

Autocomplete

The plugin allows you to set search feeds so that when typing, a query occurs in them, and if there are results, they are displayed in a pop-up window. In the window using the keyboard, you can navigate up and down. You can select the desired item either with the mouse, or by pressing tab or Enter.

Search feeds can be either simple arrays of strings, simple functions that return arrays of strings, or go to the server and return a Promise.

Simple example is mentioning employees

const names = [ '@mary', '@jain', '@entany', '@isaak', '@ivan', '@fedya', '@yakov', '@jhon', '@lena', '@elvin' ]; Jodit.make('#editor', { autocomplete: { sources: [names] } });
Copy

A more complex case of going to the server is also possible:

Jodit.make('#editor', { autocomplete: { sources: [ // Async feed as AutoCompleteCallback<IAutoCompleteItem> async (query) => fetch('./mention.php?q=' + encodeURIComponent(query)).then( (resp) => resp.json() ) ] } });
Copy

The plugin can accept several sources of information for autocomplete:

const names = [ '@mary', '@jain', '@entany', '@isaak', '@ivan', '@fedya', '@yakov', '@jhon', '@lena', '@elvin' ]; Jodit.make('#editor', { autocomplete: { sources: [ ['wysiwyg', 'editor', 'rich', 'jodit'], // Frist feed as string[] [{ value: 'Scrooge McDuck' }, { value: 'Dewey Duck' }], // Second feed as IAutoCompleteItem[] // Sync feed as AutoCompleteCallback<IAutoCompleteItem> (query) => names .filter((value) => value.indexOf(query) === 0) .map((value) => ({ title: value, value })), // Async feed as AutoCompleteCallback<IAutoCompleteItem> async (query) => fetch('./mention.php?q=' + query).then((resp) => resp.json()) ] } });
Copy

Options

sources

  • Type: AutoCompleteSource[]
  • Default: []

These are all feeds available to the plugin. When entering text, it will poll them and display the result, if any.

Type Definitions:

type AutoCompleteSource = | string[] // Simple array of strings | Promise<string[]> // Promise resolving to strings | IAutoCompleteItem[] // Array of items | Promise<IAutoCompleteItem[]> // Promise resolving to items | AutoCompleteCallback // Callback function | IAutoCompleteCustomFeed // Custom feed object interface IAutoCompleteItem<T = IDictionary> { value: string; // Required: the actual value to insert and reconciliation key title?: string; // Optional: display text in dropdown itemRenderer?: (item: T) => string | HTMLElement; insertValueRenderer?: (item: T) => string | HTMLElement; } // IMPORTANT: The 'value' field is used as a unique key for list reconciliation. // When the list updates, items with the same 'value' are reused, preserving selection. type AutoCompleteCallback = (query: string) => Promise<IAutoCompleteItem[]>; interface IAutoCompleteCustomFeed { feed: string[] | Promise<string[]> | IAutoCompleteItem[] | Promise<IAutoCompleteItem[]> | AutoCompleteCallback; itemRenderer?: (item: IAutoCompleteItem) => string | HTMLElement; insertValueRenderer?: (item: IAutoCompleteItem) => string | HTMLElement; }
Copy

The source can be:

  • A simple array of strings
  • A function that returns an array (sync or async)
  • An array of IAutoCompleteItem objects
  • A Promise that resolves to any of the above
  • An object with the feed field and optional renderers

Examples of Different Feed Types:

1. Simple string array

Jodit.make('#editor', { autocomplete: { sources: [ ['apple', 'banana', 'cherry', 'date', 'elderberry'] ] } });
Copy

2. Promise resolving to strings

const fetchFruits = async () => { const response = await fetch('/api/fruits'); return response.json(); // Returns ['apple', 'banana', ...] }; Jodit.make('#editor', { autocomplete: { sources: [ fetchFruits() // Promise<string[]> ] } });
Copy

3. Array of IAutoCompleteItem objects

const users = [ { value: '@john', title: 'John Doe' }, { value: '@jane', title: 'Jane Smith' }, { value: '@bob', title: 'Bob Johnson' } ]; Jodit.make('#editor', { autocomplete: { sources: [users] } });
Copy

4. Callback function (sync)

const searchCallback = (query) => { const items = ['item1', 'item2', 'item3']; return items .filter(item => item.includes(query)) .map(item => ({ value: item, title: item.toUpperCase() })); }; Jodit.make('#editor', { autocomplete: { sources: [searchCallback] } });
Copy

5. Callback function (async)

const asyncSearchCallback = async (query) => { const response = await fetch(`/api/search?q=${query}`); const data = await response.json(); return data.map(item => ({ value: item.id, title: item.name })); }; Jodit.make('#editor', { autocomplete: { sources: [asyncSearchCallback] } });
Copy

6. Custom feed with renderers

const customFeed = { feed: ['@alice', '@bob', '@charlie'], itemRenderer: (item) => { const div = document.createElement('div'); div.className = 'user-item'; div.innerHTML = `<b>${item.value}</b>`; return div; }, insertValueRenderer: (item) => { return `<span class="mention">${item.value}</span> `; } }; Jodit.make('#editor', { autocomplete: { sources: [customFeed] } });
Copy

7. Multiple sources combined

Jodit.make('#editor', { autocomplete: { sources: [ // Static list ['static1', 'static2'], // Dynamic callback (query) => { const emojis = ['😀', '😎', '🚀', '❤️']; return emojis .filter(e => query === ':') .map(e => ({ value: e })); }, // Async data fetch('/api/mentions').then(r => r.json()), // Custom feed with renderers { feed: async (query) => { const res = await fetch(`/api/users?q=${query}`); return res.json(); }, itemRenderer: (item) => `<img src="${item.avatar}"> ${item.name}`, insertValueRenderer: (item) => `@${item.username}` } ] } });
Copy

For example, let's make a mention of everyone's favorite characters from the Friends series.

const friends = [ { value: '@Rachel', userId: '1', name: 'Rachel Green', link: 'https://www.imdb.com/title/tt0108778/characters/nm0000098' }, { value: '@Chandler', userId: '2', name: 'Chandler Bing', link: 'https://www.imdb.com/title/tt0108778/characters/nm0001612' }, { value: '@Monica', userId: '3', name: 'Monica Geller', link: 'https://www.imdb.com/title/tt0108778/characters/nm0001073' }, { value: '@Ross', userId: '4', name: 'Dr. Ross Geller', link: 'https://www.imdb.com/title/tt0108778/characters/nm0001710' }, { value: '@Phoebe', userId: '5', name: 'Phoebe Buffay', link: 'https://www.imdb.com/title/tt0108778/characters/nm0001435' }, { value: '@Ursula', userId: '6', name: 'Ursula Buffay', link: 'https://www.imdb.com/title/tt0108778/characters/nm0001435' }, { value: '@Joey', userId: '7', name: 'Joey Tribbiani', link: 'https://www.imdb.com/title/tt0108778/characters/nm0001455' } ]; Jodit.make('#editor', { autocomplete: { sources: [ // Feed as IAutoCompleteCustomFeed<IDictionary> { feed: (query) => friends.filter( (value) => value.value.indexOf(query) === 0 || value.name.indexOf(query) !== -1 ), itemRenderer: (item) => `${item.value} (${item.name})`, insertValueRenderer: ({ value, userId, name, link }) => `<a class="mention" data-mention="${value}" data-user-id="${userId}" href="${link}">${name}</a>` } ] } });
Copy

Please note that we also set the way to display items in the list, as well as how it will be inserted into the editor when selected.

itemRenderer

  • Type: Function
  • Default: (item) => item.title ?? item.value

This function takes your list item as input and returns either a string or a ready-made HTML item to display in the list.

The function has the following signature:

interface itemRenderer { (item: T) => string | HTMLElement; }
Copy

In the example above, we set it right in the feed. However, you can define your own function for the entire plugin and all feeds.

Jodit.make('#editor', { autocomplete: { itemRenderer: (item) => `<span>${item.value} (${item.name})</span>`, sources: [ // feeds ... ] } });
Copy

insertValueRenderer

  • Type: Function
  • Default: (item) => item.value + '&nbsp;'

The function formats the result to be inserted into the editor. You are free to transform the selected value as desired.

The function has a signature similar to itemRenderer and can also return a ready-made HTMLElement;

interface insertValueRenderer { (item: T) => string | HTMLElement; }
Copy
Jodit.make('#editor', { autocomplete: { insertValueRenderer: (item) => { const a = document.createElement('a'); a.href = item.link; a.innerText = item.name; return a; }, sources: [ // feeds ... ] } });
Copy

maxItems

  • Type: Number
  • Default: 50

The maximum number of items that the autocomplete list will display.

Jodit.make('#editor', { autocomplete: { maxItems: 10, // Show only 10 items even if more matches found sources: [ // Large dataset ['item1', 'item2', 'item3' /* ... many more items ... */] ] } });
Copy

isMatchedQuery

  • Type: Function
  • Default: (query, value) => value.toLowerCase().indexOf(query.toLowerCase()) === 0

For cases where feed is specified as a regular array, this method allows you to describe the search for matches in it.

const names = [ '@mary', '@jain', '@entany', '@isaak', '@ivan', '@fedya', '@yakov', '@jhon', '@lena', '@elvin' ]; Jodit.make('#editor', { autocomplete: { isMatchedQuery: (q, value) => { value = value.substr(1); return value.toLocaleUpperCase().includes(q.toLocaleUpperCase()); // Full text search }, sources: [names] } });
Copy

Events

autocomplete

Run query checked and return array of matched items.

const editor = Jodit.make('#editor'); const items = editor.events.fire('autocomplete', 'some query'); console.log(items); // all found results
Copy

select.autocomplete

Fired on item selection by keyboard or by mouse.

const editor = Jodit.make('#editor'); editor.events.on('select.autocomplete', (selectedItem) => { console.log(selectedItem); });
Copy

registerAutocompleteSource

The main event for registering your own autocomplete sources.

const editor = Jodit.make('#editor'); await editor.waitForReady(); // Because plugin Autocomplete can be loaded asynchronously const languages = [ 'ActionScript', 'AppleScript', 'Asp', 'BASIC', 'Erlang', 'Fortran', 'Haskell', 'Java', 'JavaScript', 'Scala' ]; const sourceClb = (query) => languages .filter((value) => value.indexOf(query) === 0) .map((value) => ({ title: value, value })); editor.events.fire('registerAutocompleteSource', sourceClb); // To unregister the source editor.events.fire('unregisterAutocompleteSource', sourceClb);
Copy

Performance and List Reconciliation

The autocomplete plugin uses an efficient reconciliation algorithm to update the dropdown list while preserving user selection and minimizing DOM operations.

Key Features:

  • Smart list updates: When the list changes, only modified items are re-rendered
  • Selection preservation: The selected item is preserved by value when the list updates
  • Minimal DOM operations: Reuses existing DOM elements when possible
  • Handles duplicates: Correctly manages lists with duplicate values

Performance Tips:

  1. Use maxItems: Limit the number of displayed items to improve rendering performance
  2. Implement debouncing: For server requests, consider implementing debouncing in your feed function
  3. Optimize search: Use efficient filtering algorithms in your feed callbacks
  4. Preload data: For small datasets, preload data instead of making server requests

Example with debouncing:

const debounce = (func, delay) => { let timeoutId; return (...args) => { clearTimeout(timeoutId); return new Promise((resolve) => { timeoutId = setTimeout(() => resolve(func(...args)), delay); }); }; }; Jodit.make('#editor', { autocomplete: { sources: [ debounce(async (query) => { const response = await fetch(`/api/search?q=${query}`); return response.json(); }, 300) ] } });
Copy

Screenshots

Demo

Enter @a or friends name ex. @Mon