Choose interaction capabilities and permissions
Choose instance actions, customize client-side decisions, and enforce authorization in your backend.
Start with your application's verified permissions. Use them to configure the Editor's available actions, then enforce the same policy at the trusted boundary where your application accepts changes.
Choose the layer
| Layer | Use it for | Who owns the decision |
|---|---|---|
interaction | Set the actions this Editor instance allows, such as reading comments or deciding tracked changes. | Your application configures client-side capabilities. |
permissionResolver | Customize supported client-side checks for a particular comment, tracked change, or versioning action. | Your synchronous callback overrides or preserves a built-in decision. |
| Trusted backend | Authorize document reads, saves, collaboration room access, and changes your service accepts. | Your server verifies identity and enforces application policy. |
Use ui to choose what SuperDoc renders. Hiding the comments panel with ui.comments: false does not remove comments
or grant or revoke an action. Custom comments controls still need to respect available
actions and handle the controller's result.
Set the instance capabilities
interaction.comments.level is the highest comment interaction level the instance allows. Levels are cumulative;
specific actions can still be blocked by their permission checks or document state.
| Level | Available comment actions before other checks |
|---|---|
read | Read existing threads. |
write | Read, create, reply, edit, and delete. |
resolve | All write actions, plus resolve and reopen. This is the default. |
These levels also apply in documentMode: 'viewing'. The default resolve level allows comment creation, replies,
editing your own comments and replies, deletion, and resolve/reopen when permission and command checks allow.
Creating a comment from document text requires allowSelectionInViewMode: true. Your role and permissionResolver
determine whether you can delete other authors' comments or resolve their threads. Viewing mode keeps document text
read-only. For a viewer with read-only comments too, set interaction.comments.level: 'read';
see the read-only viewer configuration.
Comment levels do not control tracked-change decisions. Set interaction.trackedChanges.allowDecisions: false to
block accept and reject in this instance. Its default is true; document mode and command availability can still
block decisions. Choosing suggesting controls how new edits are recorded, not who may decide existing proposals.
For example, use write when contributors may discuss a passage but should not resolve its thread. Use resolve
when reviewers may resolve threads, then use the resolver for supported checks that differ by author or action.
See Review workflows for proposing changes without deciding them.
Customize a specific client-side check
Set permissionResolver at the top level of the Editor configuration. The callback is synchronous: return true
or false to override a permission decision, or undefined to preserve defaultDecision. An async callback is not
supported. The default uses the configured role and isInternal values.
The callback receives permission, role, isInternal, defaultDecision, comment, trackedChange, currentUser,
and superdoc. Entity values may be null when the check has no corresponding entity. The configured browser user
and role describe this client; they are not proof of authenticated identity.
In the Quickstart project, add these options alongside the existing document, user, and export configuration:
import type { Config } from 'superdoc';
export const permissionOptions = {
interaction: {
comments: { level: 'resolve' },
trackedChanges: { allowDecisions: true },
},
permissionResolver: ({ permission }) => {
switch (permission) {
case 'COMMENTS_DELETE_OTHER':
case 'REJECT_OTHER':
return false;
default:
return undefined;
}
},
} satisfies Pick<Config, 'interaction' | 'permissionResolver'>;
This example keeps comment resolution available but denies deleting someone else's comment and rejecting someone
else's tracked change. Other checks retain their built-in decision. In Vanilla, spread permissionOptions into
new SuperDoc(); in React, spread it onto SuperDocEditor.
A resolver allowance cannot override an interaction restriction or make an unavailable action possible. A denied
check can further restrict an action that the instance otherwise permits. For example, returning true for
RESOLVE_OTHER does not make comment resolution available at level write.
Permission keys
These are the current permission constants. They do not mean every UI surface or programmatic method invokes every
check. In particular, COMMENTS_OVERFLOW is the own-comment constant's literal value; it has no _OWN suffix.
| Keys | Check |
|---|---|
RESOLVE_OWN, RESOLVE_OTHER | Resolve or reopen a comment, or accept a tracked change, according to authorship. |
REJECT_OWN, REJECT_OTHER | Reject a tracked change according to authorship. |
COMMENTS_DELETE_OWN, COMMENTS_DELETE_OTHER | Delete a comment according to authorship. |
COMMENTS_OVERFLOW, COMMENTS_OVERFLOW_OTHER | Comment overflow permission constants; current built-in comment action availability checks the actions themselves. |
UPLOAD_VERSION, VERSION_HISTORY | Versioning permission constants; your versioning integration must apply its policy where it handles these actions. |
For custom UI, check action availability and inspect mutation receipts. A generic permission check alone does not
establish that an action can run. Direct Document API calls and headless operations are separate execution surfaces:
do not assume permissionResolver intercepts every mutation. Authorize application-owned commands before invoking
them. See Document API comments and custom review controls.
Enforce policy where changes are accepted
Both Editor mechanisms run in the browser and are not an authorization boundary. Someone who controls the client can change its configuration or send a request without using your buttons.
Your backend must verify the authenticated identity and document access before serving a document, accepting a save, or allowing a collaboration connection. Protect separate file endpoints as well as the room. Use Control room access for the collaboration connection example.
If your policy allows discussion but forbids changing document text, granting save access alone does not enforce that distinction. Accepting arbitrary DOCX uploads or unrestricted collaboration updates cannot guarantee comment-only changes. Your trusted service must validate the permitted changes or expose operations it can authorize individually. Choose a collaboration provider and persistence path that can enforce the policy you need.
Keep client settings aligned with that policy for a clear user experience. Do not treat a hidden button, a resolver result, or a browser-supplied author as evidence that the backend request is authorized.
Word restriction modes and named exceptions
editor.doc.protection.setEditingRestriction({ mode }) authors readOnly, comments,
trackedChanges, or forms in the DOCX. Always inspect the returned
state.editingRestriction.runtimeEnforced: V2 enforces readOnly; the other
three modes are saved for Word and currently report false in SuperDoc.
In particular, trackedChanges does not switch SuperDoc to suggesting mode;
direct edits can be saved without revision markup.
enforced: true describes the saved Word setting, not a browser authorization
guarantee. Use clearEditingRestriction() to disable the saved restriction.
Your application owns the editor roster and authenticated user. The
superdoc helpers accept that roster explicitly, so they work with
Config.users, superdoc.users, or an application directory without treating
presence or comment authors as a directory:
import { listPermissionRangeEditors, resolvePermissionRangeEditor } from 'superdoc';
const choices = listPermissionRangeEditors(superdoc.users);
const selected = resolvePermissionRangeEditor(superdoc.users, selectedUserId);
if (selected.status === 'resolved') {
await editor.doc.permissionRanges.create({ target: selection, principal: selected.principal });
}Discovery includes ambiguous entries so the host can disable conflicting
choices. Resolution returns unknown for absent IDs and ambiguous for duplicate
IDs, duplicate emails, or email/ID collisions; neither result contains a grant.
Names are display labels. Resolution uses an exact host ID or a case-insensitive
email and serializes the email into Word's w:ed when supplied. An ID without an
email remains a host-specific Word editor string; it does not establish that
Word recognizes the same account. Word account authentication remains external.
Set Config.user to the active host user. In a readOnly document, a
well-formed permission range covering the full edit allows that user's exact
id, their email ignoring case, or everyone. Overlapping grants are additive:
a grant to another editor does not cancel a matching user or everyone grant.
Users without a matching grant remain refused. This works without a
permissionResolver; tracked-change author overrides do not
change the active permission identity. Imported unsupported groups, missing or
conflicting identities, and malformed markers block intersecting edits even
when another range grants access. Body permissions are supported in collaboration;
editing permission markers in headers and footers during collaboration remains unsupported.
Saved editor IDs and the host roster are different things.
editor.doc.permissionRanges.list() reads document exceptions; the helpers
resolve host identities and do not authenticate users, provision Word accounts,
or change server access controls.