How to implement autocomplete feature in TinyMCE
Tags: richtexteditor, javascript, webdev, tutorial
Published: 2023-09-29 18:59:44

TinyMCE's Autocompleter works using matched text patterns. The text pattern is matched to data returned by a JavaScript promise. A trigger character causes the fetch function to run, and the matched text the writer types after the trigger character is collected and passed to the fetch function. The function returns a promise that contains the matched results found in the list of options.

There is a specific Autocompleter API available in TinyMCE that handles autocompletion. It makes use of a number of options, some are required, like the onAction option, and others are not required, but change the appearance, or the user experience such as the maxResult functions (this limits by the number of results that should be fetched based on the writer’s input).

**NOTE:** If using an earlier version of TinyMCE before 6.2, use the ch option. Versions after this release should use the trigger option. You can check your TinyMCE version in the dashboard of your TinyMCE account, by checking the TinyMCE CDN link, or using the tinyMCE.majorVersion command in the developer console.

### How to implements this?

#### Step 1
Start by making a new index.html file in your development environment

#### Step 2
Copy the following started HTML into the file, which has a textarea set up for TinyMCE:

```html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Autocomplete feature in TinyMCE</title>
    </head>
    <body>
        <textarea id="editor">
            <div class="editable">Try out autocomplete</div>
        </textarea>
    </body>
</html>
```

#### Step 3
Configure TinyMCE into the demo using the CDN link to TinyMCE cloud:
```html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Autocompelte Test 1 TinyMCE</title>
        <script src="https://cdn.tiny.cloud/1/your-api-key/tinymce/6/tinymce.min.js" referrerpolicy="origin"></script>
```

#### Step 4
Replace the "your-api-key" string with your TinyMCE API key. You can [sign up for a FREE TinyMCE API key](https://www.tiny.cloud/auth/signup/?utm_campaign=devrel_devto_tiny&utm_source=devto&utm_medium=blog) using your GitHub or Google account, and your key comes with a 14-day free trial of TinyMCE's premium plugins (it also prevents any domain name errors appearing in the console).

#### Step 5
Copy the following TinyMCE init script into your file:
```html
<script>
            tinymce.init({
                selector: '#editor',
                plugins: 'advcode, advlist, advtable, anchor, autosave, autolink, checklist, directionality, editimage, export, formatpainter, image, insertdatetime, link, linkchecker, lists, media, mediaembed, nonbreaking, pagebreak, permanentpen, powerpaste, searchreplace, table, tableofcontents, tinymcespellchecker, visualblocks, wordcount',
                toolbar: 'undo redo print spellcheckdialog formatpainter | blocks fontfamily fontsize | bold italic underline forecolor backcolor | link image | alignleft aligncenter alignright alignjustify lineheight | checklist bullist numlist indent outdent | removeformat',
                editable_root: false,
                editable_class: 'editable',
                setup: (editor) => { }
```

#### Step 6
Add the autocompleter with the editor registry parameters within the setup option. The following gives the autocompleter a name and [sets up the required options](https://www.tiny.cloud/docs/tinymce/6/autocompleter/?utm_campaign=devrel_devto_tiny&utm_source=devto&utm_medium=blog#options):
```javascript
setup: (editor) => {
                    editor.ui.registry.addAutocompleter("Demo-0", {
                        trigger: '/',
                        minChars: 1,
                        columns: 'auto',
                        onAction:
                    })
                  }
```

#### Step 7
Add the autocompleterAPI options to complete setting up the onAction option:

```javascript
setup: (editor) => {
  editor.ui.registry.addAutocompleter("Demo-0", {
    trigger: "/",
    minChars: 1,
    columns: "auto",
    onAction: (onAction = (autocompleteApi, rng, value) => {
      editor.selection.setRng(rng);
      editor.insertContent(value);
      autocompleteApi.hide();
    }),
  });
};
```

### Step 8
Configure the fetch option, including the Promise option. The promise option contains two important constants that the autocompleter needs to filter the matched characters:

```javascript
setup: (editor) => {
  editor.ui.registry.addAutocompleter("Demo-0", {
    trigger: "/",
    minChars: 1,
    columns: "auto",
    onAction: (onAction = (autocompleteApi, rng, value) => {
      editor.selection.setRng(rng);
      editor.insertContent(value);
      autocompleteApi.hide();
    }),
    fetch: (pattern) => {
      return new Promise((resolve) => {
        {
          const getMatchedChars = (pattern) => {
            return specialChars.filter(
              (char) => char.text.indexOf(pattern) !== -1
            );
          };
          const results = getMatchedChars(pattern).map((char) => ({
            type: "autocompleteitem",
            value: char.value,
            text: char.value,
            icon: char.value,
          }));
        }
      });
    },
  });
};
```

#### Step 9
Add the resolve method to complete the promise:
```javascript
setup: (editor) => {
  editor.ui.registry.addAutocompleter("Demo-0", {
    trigger: "/",
    minChars: 1,
    columns: "auto",
    onAction: (onAction = (autocompleteApi, rng, value) => {
      editor.selection.setRng(rng);
      editor.insertContent(value);
      autocompleteApi.hide();
    }),
    fetch: (pattern) => {
      return new Promise((resolve) => {
        {
          const getMatchedChars = (pattern) => {
            return specialChars.filter(
              (char) => char.text.indexOf(pattern) !== -1
            );
          };
          const results = getMatchedChars(pattern).map((char) => ({
            type: "autocompleteitem",
            value: char.value,
            text: char.value,
            icon: char.value,
          }));
          resolve(results);
        }
      });
    },
  });
};
```

#### Step 10
Copy the following list of options for the autocompleter, pasting it into the demo before the TinyMCE init script:

```javascript
<script>
            const specialChars = [
               { text: 'exclamation mark', value: '!' },
               { text: 'at', value: '@' },
               { text: 'hash', value: '#' },
               { text: 'dollars', value: '$' },
               { text: 'percent sign', value: '%' },
               { text: 'caret', value: '^' },
               { text: 'ampersand', value: '&' },
               { text: 'asterisk', value: '*' }
             ]
            tinymce.init({ ... })
```

#### Step 11
Save the changes, and then test out the autocompleter by running the demo index.html file in your browser with a testing command such as the Python or PHP options:


![Auto Completer Demo Gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jebjm2njgkviucsrvyp0.gif)

### Next steps for your autocomplete feature
The autocompleter example here uses only the essential options. There are further ways you can customize the autocomplete feature:

- Changing the direction of the autocompleter window to horizontal or vertical view
- Adding in an image for the autocompleter
- Add more columns to increase the number of choices available

You can keep experimenting with the options available until you find the ideal configuration for your app, your use case, and your customers. Sign up for an API key to further test out the different plugins TinyMCE has available.

For more information, [contact the TinyMCE team](https://www.tiny.cloud/contact/?utm_campaign=devrel_devto_tiny&utm_source=devto&utm_medium=blog), who can help you find the ideal combination of autocompleter or plugins for your project.