---
title: "Configuring the Comments plugin in callback mode"
description: "Information on configuring the Comments plugin in callback mode"
canonical_url: "https://www.tiny.cloud/docs/tinymce/latest/comments-callback-mode/"
md_url: "https://www.tiny.cloud/docs/tinymce/5/comments-callback-mode/index.md"
version: "5"
last_updated: "2025-04-07T04:36:27Z"
tokens: 6448
---
Important This page documents TinyMCE 5. For new projects, Tiny recommends using the latest, most up-to-date version. [See TinyMCE 8 documentation](../../latest/comments-callback-mode/).
# Configuring the Comments plugin in callback mode

**Callback mode** is the default mode for the Comments plugin. In the callback mode, callback functions are required to save user comments on a server. The Comments functions (create, reply, edit, delete comment, delete all conversations, resolve, and lookup) are configured differently depending upon the server-side storage configuration.

## Interactive example

**Example**

```js
/********************************
 *   Demo-specific configuration  *
 ********************************/

const userDb = {
  'michaelcook': {
    id: 'michaelcook',
    name: 'Michael Cook',
    fullName: 'Michael Cook',
    description: 'Product Owner',
  },
  'kalebwilson': {
    id: 'kalebwilson',
    name: 'Kaleb Wilson',
    fullName: 'Kaleb Wilson',
    description: 'Marketing Director',
  }
};

const currentUid = 'kalebwilson';
const adminUid = 'michaelcook';

const now = new Date();
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000).toISOString();
const anhourago = new Date(now.getTime() - 60 * 60 * 1000).toISOString();

const fillAuthorInfo = (id, fullName) => ({
  author: id,
  authorName: fullName,
});

const getAuthorInfo = (uid) => {
  const user = userDb[uid];
  if (user) {
    return fillAuthorInfo(user.id, user.fullName);
  }
  return {
    author: uid,
    authorName: uid,
  };
}

const conversationDb = {
  'mce-conversation_19679600221621399703915': {
    uid: 'mce-conversation_19679600221621399703915',
    comments: [{
      uid: 'mce-conversation_19679600221621399703915',
      ...getAuthorInfo(currentUid),
      content: `What do you think about this?`,
      createdAt: yesterday,
      modifiedAt: yesterday
    }, {
      uid: 'mce-conversation_19679600221621399703917',
      ...getAuthorInfo(adminUid),
      content: `I think this is a great idea!`,
      createdAt: anhourago,
      modifiedAt: anhourago,
    }]
  },
  'mce-conversation_420304606321716900864126': {
    uid: 'mce-conversation_420304606321716900864126',
    comments: [{
      uid: 'mce-conversation_420304606321716900864126',
      ...getAuthorInfo(adminUid),
      content: `Please revise this sentence, exclamation points are unprofessional!`,
      createdAt: yesterday,
      modifiedAt: anhourago
    }]
  }
};

const fakeDelay = 200;
const randomString = () => crypto.getRandomValues(new Uint32Array(1))[0].toString(36).substring(2, 14);

const resolvedConversationDb = {};

/********************************
 *   Tiny Comments functions    *
 * (must call "done" or "fail") *
 ********************************/

const tinycomments_create = (req, done, fail) => {
  if (req.content === 'fail') {
    fail(new Error('Something has gone wrong...'));
  } else {
    const uid = 'annotation-' + randomString();
    conversationDb[uid] = {
      uid,
      comments: [{
        uid,
        ...getAuthorInfo(currentUid),
        content: req.content,
        createdAt: req.createdAt,
        modifiedAt: req.createdAt
      }]
    };
    setTimeout(() => done({ conversationUid: uid }), fakeDelay);
  }
};

const tinycomments_reply = (req, done) => {
  const replyUid = 'annotation-' + randomString();
  conversationDb[req.conversationUid].comments.push({
    uid: replyUid,
    ...getAuthorInfo(currentUid),
    content: req.content,
    createdAt: req.createdAt,
    modifiedAt: req.createdAt
  });
  setTimeout(() => done({ commentUid: replyUid }), fakeDelay);
};

const tinycomments_delete = (req, done) => {
  if (currentUid === adminUid) { // Replace wth your own logic, e.g. check if user created the conversation
    delete conversationDb[req.conversationUid];
    setTimeout(() => done({ canDelete: true }), fakeDelay);
  } else {
    setTimeout(() => done({ canDelete: false, reason: 'Must be admin user' }), fakeDelay);
  }
};

const tinycomments_resolve = (req, done) => {
  const conversation = conversationDb[req.conversationUid];
  if (currentUid === conversation.comments[0].author) { // Replace wth your own logic, e.g. check if user has admin priveleges
    delete conversationDb[req.conversationUid];
    setTimeout(() => done({ canResolve: true }), fakeDelay);
  } else {
    setTimeout(() => done({ canResolve: false, reason: 'Must be conversation author' }), fakeDelay);
  }
};

const tinycomments_delete_comment = (req, done) => {
  const oldcomments = conversationDb[req.conversationUid].comments;
  let reason = 'Comment not found';

  const newcomments = oldcomments.filter((comment) => {
    if (comment.uid === req.commentUid) { // Found the comment to delete
      if (currentUid === comment.author) { // Replace with your own logic, e.g. check if user has admin privileges
        return false; // Remove the comment
      } else {
        reason = 'Not authorised to delete this comment'; // Update reason
      }
    }
    return true; // Keep the comment
  });
  if (newcomments.length === oldcomments.length) {
    setTimeout(() => done({ canDelete: false, reason }), fakeDelay);
  } else {
    conversationDb[req.conversationUid].comments = newcomments;
    setTimeout(() => done({ canDelete: true }), fakeDelay);
  }
};

const tinycomments_edit_comment = (req, done) => {
  const oldcomments = conversationDb[req.conversationUid].comments;
  let reason = 'Comment not found';
  let canEdit = false;

  const newcomments = oldcomments.map((comment) => {
    if (comment.uid === req.commentUid) { // Found the comment to delete
      if (currentUid === comment.author) { // Replace with your own logic, e.g. check if user has admin privileges
        canEdit = true; // User can edit the comment
        return { ...comment, content: req.content, modifiedAt: new Date().toISOString() }; // Update the comment
      } else {
        reason = 'Not authorised to edit this comment'; // Update reason
      }
    }
    return comment; // Keep the comment
  });

  if (canEdit) {
    conversationDb[req.conversationUid].comments = newcomments;
    setTimeout(() => done({ canEdit }), fakeDelay);
  } else {
    setTimeout(() => done({ canEdit, reason }), fakeDelay);
  }
};

const tinycomments_delete_all = (req, done) => {
  const conversation = conversationDb[req.conversationUid];
  if (currentUid === conversation.comments[0].author) { // Replace wth your own logic, e.g. check if user has admin priveleges
    delete conversationDb[req.conversationUid];
    setTimeout(() => done({ canDelete: true }), fakeDelay);
  } else {
    setTimeout(() => done({ canDelete: false, reason: 'Must be conversation author' }), fakeDelay);
  }
};

const tinycomments_lookup = (req, done) => {
  setTimeout(() => {
    done({
      conversation: {
        uid: conversationDb[req.conversationUid].uid,
        comments: [...conversationDb[req.conversationUid].comments]
      }
    });
  }, fakeDelay);
};


tinymce.init({
  selector: 'textarea#comments-callback',
  height: 800,
  toolbar: 'addcomment showcomments code | bold italic underline',
  menubar: 'file edit view insert format tools tc help',
  menu: {
    tc: {
      title: 'TinyComments',
      items: 'addcomment showcomments deleteallconversations'
    }
  },
  plugins: ['tinycomments', 'help', 'code', 'quickbars', 'link', 'lists', 'image'],
  quickbars_selection_toolbar: 'alignleft aligncenter alignright | addcomment showcomments',
  quickbars_image_toolbar: 'alignleft aligncenter alignright | rotateleft rotateright | imageoptions',
  sidebar_show: 'showcomments',
  tinycomments_mode: 'callback',
  tinycomments_create,
  tinycomments_reply,
  tinycomments_delete,
  tinycomments_resolve,
  tinycomments_delete_all,
  tinycomments_lookup,
  tinycomments_delete_comment,
  tinycomments_edit_comment,
});
```

### How the comments plugin works in callback mode

All options accept functions incorporating `done` and `fail` callbacks as parameters. The function return type is not important, but all functions must call exactly one of these two callbacks: `fail` or `done`.

- The `fail` callback takes either a string or a JavaScript Error type.
- The `done` callback takes an argument specific to each function.

Most (create, reply, and edit) functions require an `id` identifying the **current author**.

Current author The Comments plugin does not know the name of the current user. Determining the current user and storing the comment related to that user, has to be configured by the developer.

After a user comments (triggering `tinycomments_create` for the first comment, or `tinycomments_reply` for subsequent comments), the Comments plugin requests the updated conversation using `tinycomments_lookup`, which should now contain the additional comment with the proper author.

## Configuration options

### Required options

When using callback mode, the Comments plugin requires callback functions for the following options:

- [`tinycomments_create`](#tinycomments_create)
- [`tinycomments_reply`](#tinycomments_reply)
- [`tinycomments_edit_comment`](#tinycomments_edit_comment)
- [`tinycomments_delete_comment`](#tinycomments_delete_comment)
- [`tinycomments_delete`](#tinycomments_delete)
- [`tinycomments_delete_all`](#tinycomments_delete_all)
- [`tinycomments_lookup`](#tinycomments_lookup)

The [`tinycomments_resolve`](#tinycomments_resolve) option is *optional*.

### `tinycomments_create`

The Comments plugin uses the `tinycomments_create` function to create a comment.

The `tinycomments_create` function saves the comment as a new conversation and returns a unique conversation ID via the `done` callback. If an unrecoverable error occurs, it should indicate this with the fail callback.

The `tinycomments_create` function is given a request (req) object as the first parameter, which has these fields:

`content` The content of the comment to create.

`createdAt` The date the comment was created.

The `done` callback should accept the following object:

```ts
{
  conversationUid: string, // the new conversation uid
  // Optional error callback which will be run if the new conversation could not be created
  onError: function (err) { ... },
  // Optional success callback which will be run when the new conversation is successfully created
  onSuccess: function (uid) { ... }
}
```
For example:

```js
function create_comment(ref, done, fail) {
  let content = ref.content;
  let createdAt = ref.createdAt;

  fetch('https://api.example/conversations/', {
    method: 'POST',
    body: JSON.stringify({ content: content, createdAt: createdAt }),
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
  })
    .then((response) => {
      if (!response.ok) {
        throw new Error('Failed to create comment');
      }
      return response.json();
    })
    .then((ref2) => {
      let conversationUid = ref2.conversationUid;
      done({ conversationUid: conversationUid });
    })
    .catch((e) => {
      fail(e);
    });
}

tinymce.init({
  selector: '#editor',
  plugins: 'tinycomments',
  tinycomments_mode: 'callback',
  tinycomments_create: create_comment, // Add the callback to TinyMCE
  tinycomments_reply: reply_comment,
  tinycomments_edit_comment: edit_comment,
  tinycomments_delete: delete_comment_thread,
  tinycomments_delete_all: delete_all_comment_threads,
  tinycomments_delete_comment: delete_comment,
  tinycomments_lookup: lookup_comment
});
```

### `tinycomments_reply`

The Comments plugin uses the `tinycomments_reply` function to reply to a comment.

The `tinycomments_reply` function saves the comment as a reply to an existing conversation and returns via the `done` callback once successful. Unrecoverable errors are communicated to TinyMCE by calling the `fail` callback instead.

The `tinycomments_reply` function is given a request (req) object as the first parameter, which has these fields:

`conversationUid` The uid of the conversation the reply is targeting.

`content` The content of the comment to create.

`createdAt` The date the comment was created.

The `done` callback should accept the following object:

```ts
{
  commentUid: string // the value of the new comment uid
}
```
For example:

```js
function reply_comment(ref, done, fail) {
  let conversationUid = ref.conversationUid;
  let content = ref.content;
  let createdAt = ref.createdAt;

  fetch('https://api.example/conversations/' + conversationUid, {
    method: 'POST',
    body: JSON.stringify({ content: content, createdAt: createdAt }),
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
  })
    .then((response) => {
      if (!response.ok) {
        throw new Error('Failed to reply to comment');
      }
      return response.json();
    })
    .then((ref2) => {
      let commentUid = ref2.commentUid;
      done({ commentUid: commentUid });
    })
    .catch((e) => {
      fail(e);
    });
}

tinymce.init({
  selector: '#editor',
  plugins: 'tinycomments',
  tinycomments_mode: 'callback',
  tinycomments_create: create_comment,
  tinycomments_reply: reply_comment, // Add the callback to TinyMCE
  tinycomments_edit_comment: edit_comment,
  tinycomments_delete: delete_comment_thread,
  tinycomments_delete_all: delete_all_comment_threads,
  tinycomments_delete_comment: delete_comment,
  tinycomments_lookup: lookup_comment
});
```

### `tinycomments_edit_comment`

The Comments plugin uses the `tinycomments_edit_comment` function to edit a comment.

The `tinycomments_edit_comment` function allows updating or changing existing comments and returns via the `done` callback once successful. Unrecoverable errors are communicated to TinyMCE by calling the `fail` callback instead.

The `tinycomments_edit_comment` function is given a request (req) object as the first parameter, which has these fields:

`conversationUid` The uid of the conversation the reply is targeting.

`commentUid` The uid of the comment to edit (it can be the same as `conversationUid` if editing the first comment in a conversation).

`content` The content of the comment to create.

`modifiedAt` The date the comment was modified.

The `done` callback should accept the following object:

```ts
{
  canEdit: boolean, // whether or not the Edit succeeded
  reason: string? // an optional string explaining why the edit was not allowed (if canEdit is false)
}
```
For example:

```js
function edit_comment(ref, done, fail) {
  let conversationUid = ref.conversationUid;
  let commentUid = ref.commentUid;
  let content = ref.content;
  let modifiedAt = ref.modifiedAt;

  fetch(
    'https://api.example/conversations/' + conversationUid + '/' + commentUid,
    {
      method: 'PUT',
      body: JSON.stringify({ content: content, modifiedAt: modifiedAt }),
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
    }
  )
    .then((response) => {
      if (!response.ok) {
        throw new Error('Failed to edit comment');
      }
      return response.json();
    })
    .then((ref2) => {
      let canEdit = ref2.canEdit;
      done({ canEdit: canEdit });
    })
    .catch((e) => {
      fail(e);
    });
}

tinymce.init({
  selector: '#editor',
  plugins: 'tinycomments',
  tinycomments_mode: 'callback',
  tinycomments_create: create_comment,
  tinycomments_reply: reply_comment,
  tinycomments_edit_comment: edit_comment, // Add the callback to TinyMCE
  tinycomments_delete: delete_comment_thread,
  tinycomments_delete_all: delete_all_comment_threads,
  tinycomments_delete_comment: delete_comment,
  tinycomments_lookup: lookup_comment
});
```

### `tinycomments_resolve`

> **Note:** This feature is only available for TinyMCE 5.8 and later.
This option adds a *Resolve Conversation* item to the dropdown menu of the first comment in a conversation.

The `tinycomments_resolve` function should asynchronously return a flag indicating whether the comment thread was resolved using the `done` callback. Unrecoverable errors are communicated to TinyMCE by calling the `fail` callback instead.

The `tinycomments_resolve` function is passed a (`req`) object as the first parameter, which contains the following key-value pair:

`conversationUid` The uid of the conversation the reply is targeting.

The `done` callback should accept the following object:

```ts
{
  canResolve: boolean // whether or not the conversation can be resolved
  reason?: string // an optional string explaining why resolving was not allowed (if canResolve is false)
}
```

> **Note:** Failure to resolve due to permissions or business rules should be indicated by `canResolve: false`, while unexpected errors should be indicated using the `fail` callback.
For example:

```js
function resolve_comment_thread(ref, done, fail) {
  let conversationUid = ref.conversationUid;
  fetch('https://api.example/conversations/' + conversationUid, {
    method: 'PUT',
  }).then((response) => {
    if (response.ok) {
      done({ canResolve: true });
    } else if (response.status === 403) {
      done({ canResolve: false });
    } else {
      fail(new Error('Something has gone wrong...'));
    }
  });
}

tinymce.init({
  selector: '#editor',
  plugins: 'tinycomments',
  tinycomments_mode: 'callback',
  tinycomments_create: create_comment,
  tinycomments_reply: reply_comment,
  tinycomments_edit_comment: edit_comment,
  tinycomments_resolve: resolve_comment_thread, // Add the callback to TinyMCE
  tinycomments_delete: delete_comment_thread,
  tinycomments_delete_all: delete_all_comment_threads,
  tinycomments_delete_comment: delete_comment,
  tinycomments_lookup: lookup_comment
});
```

### `tinycomments_delete_comment`

The `tinycomments_delete_comment` function should asynchronously return a flag indicating whether the comment or comment thread was removed using the `done` callback. Unrecoverable errors are communicated to TinyMCE by calling the `fail` callback instead.

The `tinycomments_delete_comment` function is given a request (req) object as the first parameter, which has these fields:

`conversationUid` The uid of the conversation the reply is targeting.

`commentUid` The uid of the comment to delete (cannot be the same as `conversationUid`).

The `done` callback should accept the following object:

```ts
{
  canDelete: boolean, // whether or not an individual comment can be deleted
  reason: string? // an optional reason explaining why the delete was not allowed (if canDelete is false)
}
```

> **Note:** Failure to delete due to permissions or business rules is indicated by "false", while unexpected errors should be indicated using the "fail" callback.
For example:

```js
function delete_comment(ref, done, fail) {
  let conversationUid = ref.conversationUid;
  let commentUid = ref.commentUid;

  fetch(
    'https://api.example/conversations/' + conversationUid + '/' + commentUid,
    {
      method: 'DELETE',
    }
  ).then((response) => {
    if (response.ok) {
      done({ canDelete: true });
    } else if (response.status === 403) {
      done({ canDelete: false });
    } else {
      fail(new Error('Something has gone wrong...'));
    }
  });
}

tinymce.init({
  selector: '#editor',
  plugins: 'tinycomments',
  tinycomments_mode: 'callback',
  tinycomments_create: create_comment,
  tinycomments_reply: reply_comment,
  tinycomments_edit_comment: edit_comment,
  tinycomments_delete: delete_comment_thread, // Add the callback to TinyMCE
  tinycomments_delete_all: delete_all_comment_threads,
  tinycomments_delete_comment: delete_comment,
  tinycomments_lookup: lookup_comment
});
```

### `tinycomments_delete`

The `tinycomments_delete` function should asynchronously return a flag indicating whether the comment thread was removed using the `done` callback. Unrecoverable errors are communicated to TinyMCE by calling the `fail` callback instead.

The `tinycomments_delete` function is passed a (`req`) object as the first parameter, which contains the following key-value pair:

`conversationUid` The uid of the conversation the reply is targeting.

The `done` callback should accept the following object:

```ts
{
  canDelete: boolean // whether or not the conversation can be deleted
  reason: string? // an optional string explaining why the delete was not allowed (if canDelete is false)
}
```

> **Note:** Failure to delete due to permissions or business rules is indicated by "false", while unexpected errors should be indicated using the "fail" callback.
For example:

```js
function delete_comment_thread(ref, done, fail) {
  let conversationUid = ref.conversationUid;
  fetch('https://api.example/conversations/' + conversationUid, {
    method: 'DELETE',
  }).then((response) => {
    if (response.ok) {
      done({ canDelete: true });
    } else if (response.status === 403) {
      done({ canDelete: false });
    } else {
      fail(new Error('Something has gone wrong...'));
    }
  });
}

tinymce.init({
  selector: '#editor',
  plugins: 'tinycomments',
  tinycomments_mode: 'callback',
  tinycomments_create: create_comment,
  tinycomments_reply: reply_comment,
  tinycomments_edit_comment: edit_comment,
  tinycomments_delete: delete_comment_thread, // Add the callback to TinyMCE
  tinycomments_delete_all: delete_all_comment_threads,
  tinycomments_delete_comment: delete_comment,
  tinycomments_lookup: lookup_comment
});
```

### `tinycomments_delete_all`

The `tinycomments_delete_all` function should asynchronously return a flag indicating whether all the comment threads were removed using the `done` callback. Unrecoverable errors are communicated to TinyMCE by calling the `fail` callback instead.

The `tinycomments_delete_all` function is given a request (req) object as the first parameter with no fields.

The `done` callback should accept the following object:

```ts
{
  canDelete: boolean, // whether or not all conversations can be deleted
  reason: string? // an optional string explaining why the deleteAll was not allowed (if canDelete is false)
}
```

> **Note:** Failure to delete due to permissions or business rules should be indicated by `canDelete: false`, while unexpected errors should be indicated using the `fail` callback.
For example:

```js
function delete_all_comment_threads(_req, done, fail) {
  fetch('https://api.example/conversations', {
    method: 'DELETE',
  }).then((response) => {
    if (response.ok) {
      done({ canDelete: true });
    } else if (response.status === 403) {
      done({ canDelete: false });
    } else {
      fail(new Error('Something has gone wrong...'));
    }
  });
}

tinymce.init({
  selector: '#editor',
  plugins: 'tinycomments',
  tinycomments_mode: 'callback',
  tinycomments_create: create_comment,
  tinycomments_reply: reply_comment,
  tinycomments_edit_comment: edit_comment,
  tinycomments_delete: delete_comment_thread,
  tinycomments_delete_all: delete_all_comment_threads, // Add the callback to TinyMCE
  tinycomments_delete_comment: delete_comment,
  tinycomments_lookup: lookup_comment
});
```

### `tinycomments_lookup`

The Comments plugin uses the `tinycomments_lookup` function to retrieve an existing conversation using a conversation’s unique ID.

The **Display names** configuration must be considered for the `tinycomments_lookup` function:

Display names The Comments plugin uses a simple string for the display name. For the `lookup` function, Comments expects each comment to contain the author’s display name, not a user ID, as Comments does not know the user identities. The `lookup` function should be implemented considering this and resolve user identifiers to an appropriate display name.

The conventional conversation object structure that should be returned via the `done` callback is as follows:

The `tinycomments_lookup` function is passed a (`req`) object as the first parameter, which contains the following key-value pair:

`conversationUid` The uid of the conversation the reply is targeting.

The `done` callback should accept the following object:

```ts
{
 conversation: {
   uid: string, // the uid of the conversation,
   comments: [
    {
      author: string, // author of first comment
      authorName: string, // optional - Display name to use instead of author. Defaults to using `author` if not specified
      createdAt: date, // when the first comment was created
      content: string, // content of first comment
      modifiedAt: date, // when the first comment was created/last updated
      uid: string // the uid of the first comment in the conversation
    },
    {
      author: string, // author of second comment
      authorName: string, // optional - Display name to use instead of author. Defaults to using `author` if not specified
      createdAt: date, // when the second comment was created
      content: string, // content of second comment
      modifiedAt: date, // when the second comment was created/last updated
      uid: string // the uid of the second comment in the conversation
    }
  ]
 }
}
```

> **Note:** The dates should use [ISO 8601 format](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString). This can be generated in JavaScript with: `new Date().toISOString()`.
For example:

```js
function lookup_comment({ conversationUid }, done, fail) {
  let lookup = async function () {
    let convResp = await fetch(
      'https://api.example/conversations/' + conversationUid
    );
    if (!convResp.ok) {
      throw new Error('Failed to get conversation');
    }
    let comments = await convResp.json();
    let usersResp = await fetch('https://api.example/users/');
    if (!usersResp.ok) {
      throw new Error('Failed to get users');
    }
    let { users } = await usersResp.json();
    let getUser = function (userId) {
      return users.find((u) => {
        return u.id === userId;
      });
    };
    return {
      conversation: {
        uid: conversationUid,
        comments: comments.map((comment) => {
          return {
            ...comment,
            content: comment.content,
            authorName: getUser(comment.author)?.displayName,
          };
        }),
      },
    };
  };
  lookup()
    .then((data) => {
      console.log('Lookup success ' + conversationUid, data);
      done(data);
    })
    .catch((err) => {
      console.error('Lookup failure ' + conversationUid, err);
      fail(err);
    });
}

tinymce.init({
  selector: '#editor',
  plugins: 'tinycomments',
  tinycomments_mode: 'callback',
  tinycomments_create: create_comment,
  tinycomments_reply: reply_comment,
  tinycomments_edit_comment: edit_comment,
  tinycomments_delete: delete_comment_thread,
  tinycomments_delete_all: delete_all_comment_threads,
  tinycomments_delete_comment: delete_comment,
  tinycomments_lookup: lookup_comment // Add the callback to TinyMCE
});
```

## Show the comments sidebar when TinyMCE loads

To show the comments sidebar when the editor is loaded or to display the sidebar by default, add a callback to open the sidebar once the editor 'skin' is loaded.

For example:

```js
tinymce.init({
  selector: '#editor',
  plugins: 'tinycomments',
  tinycomments_mode: 'embedded',
  tinycomments_author: currentAuthor,
  tinycomments_can_resolve: canResolveCommentsCallback,
  /* The following setup callback opens the comments sidebar when the editor loads */
  setup: function (editor) {
    editor.on('SkinLoaded', function () {
      editor.execCommand("ToggleSidebar", false, "showcomments");
    })
  }
});
```

## Configuring the commented text properties

The highlight styles are now a part of the overall content skin and are changed through customizing the skin.

TinyMCE open source project [oxide](https://github.com/tinymce/oxide/blob/master/src/less/theme/content/comments/comments.less) (default skin), defines the variables used for changing the annotation colours.

Refer to the [documentation](../creating-a-skin/#creatingaskin) for building a skin using this repo.

For more information on configuring TinyMCE formats, refer to the [formats](../content-formatting/#formats) section.
