# Comments and notes

Source: https://docx-editor.portone.io/docs/editor-api/comments-and-notes

Write, edit, resolve and read comment threads, and insert, edit and read footnotes and endnotes.

Everything on this page comes from `@portone/docx-editor/commands`.

## Comment commands [#comment-commands]

| Command                                        | What it does                                                                                                  |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `addComment(comment, at?)`                     | Adds a comment to a stretch of text: the one named, or the current selection.                                 |
| `canAddComment(state, at?)`                    | Whether that stretch, or the current selection, can receive one.                                              |
| `updateComment(id, text)`                      | Replaces a comment's text and keeps its formatting.                                                           |
| `setCommentBody(id, body)`                     | Replaces a comment's body with a formatted one.                                                               |
| `removeComment(id)`                            | Deletes a comment and its replies.                                                                            |
| `addCommentReply(id, reply)`                   | Adds a reply and reopens the thread when it was resolved.                                                     |
| `updateCommentReply(commentId, replyId, text)` | Replaces a reply's text.                                                                                      |
| `removeCommentReply(commentId, replyId)`       | Deletes one reply.                                                                                            |
| `setCommentResolved(id, resolved)`             | Marks a thread resolved or open.                                                                              |
| `selectComment(id)`                            | Selects the commented text and scrolls it into view; for a detached comment, puts the caret at its reference. |

`NewComment` is `{ text, author, authorId?, initials?, date? }`, where `date` is an ISO 8601 instant
defaulting to now, kept to the second.
The saved file records it the way Word does: the instant, and on the comment the time it reads on
the clock of the runtime that adds it, which is the author's clock only when the author runs the
editor.
Pass `author` (the display name), `initials`, and `authorId` from `mode.author`, so the comment is
recorded as that person's.

## Comment records [#comment-records]

`documentComments(state)` returns every comment in document order as a `DocumentComment`:

| Field                            | What it holds                                                                                                                                                                          |
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                             | The comment's id, which every other command takes.                                                                                                                                     |
| `author`, `authorId`, `initials` | Who wrote it, as the document records them. Null where the document names none.                                                                                                        |
| `date`                           | When it was written, as an ISO 8601 instant in UTC such as `2026-09-30T06:00:00.000Z`. A value that is not a readable date is returned as written. Null where the document names none. |
| `text`                           | The body as plain text.                                                                                                                                                                |
| `from`, `to`                     | The stretch it marks.                                                                                                                                                                  |
| `referencePos`                   | Where its reference stands in the document.                                                                                                                                            |
| `anchored`                       | Whether it still marks a stretch of text. `false` once the commented text was deleted; `from` and `to` then equal the reference position.                                              |
| `resolved`                       | Whether the thread is resolved.                                                                                                                                                        |
| `replies`                        | Its replies, each a `DocumentCommentReply` with `id`, `author`, `authorId`, `initials`, `date`, and `text`.                                                                            |

A comment added with `date` reads the same instant back.
[When a comment was written](https://docx-editor.portone.io/docs/features/comments-and-notes.md#when-a-comment-was-written) says
which instant a comment from another file reads as.
The records are read-only; copy one to change it.
[Features](https://docx-editor.portone.io/docs/features/comments-and-notes.md) describes what the built-in panel does with detached
and resolved comments.

## Formatted bodies [#formatted-bodies]

`setCommentBody` takes a `doc` node of `docxSchema`, so a composer of your own can write a bold run,
a paragraph style, or a second paragraph:

```ts
import { docxSchema } from "@portone/docx-editor";
import { setCommentBody } from "@portone/docx-editor/commands";

const body = docxSchema.nodes.doc.create(null, [
  docxSchema.nodes.paragraph.create(null, [
    docxSchema.text("Please check", [
      docxSchema.marks.run.create({ rPr: "<w:rPr><w:b/></w:rPr>" }),
    ]),
  ]),
  docxSchema.nodes.paragraph.create(null, docxSchema.text("the second line.")),
]);

setCommentBody(comment.id, body)(view.state, view.dispatch);
```

It answers `false` for a body that is not a `doc` node, one that is only whitespace, or an unknown
id.
`updateComment` and `updateCommentReply` answer `false` when the text is unchanged.

## Commenting on a range [#commenting-on-a-range]

`addComment` and `canAddComment` take an optional `{ from, to }`; the range must be a non-empty span
inside one paragraph, or the command returns `false`.
A composer that stays open while the document is edited should keep the range it opened over, map it
through `transaction.mapping` on every change, and pass it on submit.

## Who may edit a comment [#who-may-edit-a-comment]

`canEditComment(state, commentId, replyId?)` answers whether the current author may edit or delete
a comment or reply:

* A comment with a recorded identity belongs to that author; an edit by anyone else is refused.
* A comment with no recorded identity belongs to everyone.
* Re-anchoring a comment onto other text counts as editing it.
* A comment's author never changes after it is written.
* `mode.editableComments: "all"` opens every comment to the current author.
* Replying, resolving, and reopening are open to everyone under `comment` and `edit`.
* Deleting a root comment deletes its replies, whoever wrote them.

A server checks the same rules with
[`onlyCommentsChangedBy`](https://docx-editor.portone.io/docs/core/verifying-a-commenters-file.md).

## Footnotes and endnotes [#footnotes-and-endnotes]

`documentNotes(state)` returns the footnotes and endnotes the document references, in
first-reference order, each a read-only `DocumentNote` with `kind` (`"footnote"` or `"endnote"`),
`id`, `label` (as drawn, in the document's number format), `text`, and `referencePos`.
`label` is empty for a reference whose own mark follows it in the text, such as a dagger the
document wrote itself.

Each kind of note has its own four commands:

| Command                     | What it does                                                                                                                   |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `insertFootnote`            | Puts a footnote reference at the end of the selection, calling a new, empty footnote, and opens that footnote for editing.     |
| `canInsertFootnote(state)`  | Whether a footnote can go in at the end of the selection.                                                                      |
| `openFootnote(id)`          | Puts the caret just after the footnote's reference and opens the footnote for editing, which is what clicking its number runs. |
| `setFootnoteBody(id, body)` | Replaces a footnote's body with a `doc` node of `docxSchema`, as `setCommentBody` does for a comment.                          |
| `insertEndnote`             | The same for an endnote, which is drawn after the last paragraph rather than at the foot of a page.                            |
| `canInsertEndnote(state)`   | Whether an endnote can go in at the end of the selection.                                                                      |
| `openEndnote(id)`           | Puts the caret just after the endnote's reference, opens the endnote, and scrolls to it at the end of the document.            |
| `setEndnoteBody(id, body)`  | Replaces an endnote's body with a `doc` node of `docxSchema`.                                                                  |

A new note is written in the document's `FootnoteText` or `EndnoteText` paragraph style with its
number in the `FootnoteReference` or `EndnoteReference` character style where the document defines
them, and in superscript where it does not.
The insert and body commands do not apply under the `readOnly` and `comment` modes or where the
reference stands in locked content.
A body command also answers `false` for an id no reference in the text names, for a separator
entry, and for a body that says what the note already says.
It writes the body as handed and adds no reference mark, so a body that does not open with the
note's own `w:footnoteRef` or `w:endnoteRef` mark opens in Word without the note's number.

`openFootnote` and `openEndnote` apply under every mode, since opening a note is reading it, and
answer `false` only for an id no reference in the text names or a separator entry; a note opened
where the body is shut takes no typing.

There is no delete command: a transaction that deletes the last reference to a note deletes the
note with it, so one undo brings both back, and one that copies a reference gives the copy a new
id and a copy of the note.