---
title: "PDF collaboration in JavaScript | Nutrient"
canonical_url: "https://www.nutrient.io/guides/web/samples/instant-pdf-collaboration/"
md_url: "https://www.nutrient.io/guides/web/samples/instant-pdf-collaboration.md"
last_updated: "2026-05-23T00:08:18.187Z"
description: "Discover how to collaborate on PDFs using Instant comments. Explore our JavaScript example and improve your document review process today!"
---

# Collaborate on PDFs using JavaScript

Collaborate on a PDF using Instant comments.

[Get Started](https://www.nutrient.io/sdk/web/getting-started.md)

[All Samples](https://www.nutrient.io/guides/web/samples.md)

[Download](https://www.nutrient.io/guides/web/downloads.md)

[Launch Demo](https://www.nutrient.io/demo/)

---

```js

import PSPDFKit from "@nutrient-sdk/viewer";
import React from "react";

let isInstant = true;

const mentionableUsers = [
  {
    name: "Karen Anderson",
    displayName: "kanderson",
    id: "kanderson_123",
    description: "karen.anderson@gmail.com",
  },
  {
    name: "Mark Jones",
    displayName: "mjones",
    id: "mjones_456",
    description: "mark.jones@gmail.com",
  },
  {
    name: "Rachel Garcia",
    displayName: "rgarcia",
    id: "rgarcia_789",
    description: "rachel.garcia@gmail.com",
  },
  {
    name: "John Smith",
    displayName: "jsmith",
    id: "jsmith_012",
    description: "john.smith@gmail.com",
  },
  {
    name: "Emily Davis",
    displayName: "edavis",
    id: "edavis_345",
    description: "emily.davis@gmail.com",
  },
  {
    name: "Ryan Taylor",
    displayName: "",
    id: "rtaylor_678",
    description: "ryan.taylor@gmail.com",
  },
  {
    name: "Sarah Brown",
    displayName: "sbrown",
    id: "sbrown_901",
    description: "sarah.brown@gmail.com",
  },
  {
    name: "Michael Lee",
    displayName: "mlee",
    id: "mlee_234",
    description: "michael.lee@gmail.com",
  },
  {
    name: "Jennifer Wilson",
    displayName: "jwilson",
    id: "jwilson_567",
    description: "jwilson@gmail.com",
  },
  {
    name: "David Martinez",
    displayName: "dmartinez",
    id: "dmartinez_890",
    description: "david.martinez@gmail.com",
  },
];

export function load(defaultConfiguration) {
  if (!defaultConfiguration.instant &&!defaultConfiguration.document) {
    console.log(
      "Instant Comments are not supported in Nutrient Document Engine without Instant.",
    );
    isInstant = false;

    return null;
  }

  isInstant = true;

  const toolbarItems = PSPDFKit.defaultToolbarItems;

  // Enable the comments tool in the main toolbar.
  // We are placing it as the first tool on the right hand side of the toolbar.
  toolbarItems.splice(
    toolbarItems.findIndex((item) => item.type === "spacer") + 1,
    0,
    { type: "comment" },
  );

  PSPDFKit.unload(defaultConfiguration.container);

  return PSPDFKit.load({...defaultConfiguration,
    toolbarItems,
    mentionableUsers,
    initialViewState: new PSPDFKit.ViewState({
      sidebarOptions: {
        [PSPDFKit.SidebarMode.ANNOTATIONS]: {
          includeContent: [PSPDFKit.Comment],
        },
      },
    }),
  }).then((instance) => {
    console.log("Nutrient Web SDK successfully loaded!!", instance);

    const userAvatarTemplates = {};
    const commentAvatars = {};

    const creator =
      window.jwtParameters && window.jwtParameters.user_id? window.jwtParameters.user_id
        : defaultCreatorName();

    instance.addEventListener("comments.mention", (event) => {
      console.log("comments.mention", event);
    });

    instance.setAnnotationCreatorName(creator);

    instance.setIsEditableComment(
      (comment) =>
        (creator && creator.toLowerCase() === "admin") ||
        comment.creatorName === creator ||
        comment.pageIndex === null, // always allow the user to add new comments
    );

    instance.setIsEditableAnnotation(
      (annotation) =>!(annotation instanceof PSPDFKit.Annotations.CommentMarkerAnnotation) ||
        annotation.creatorName === creator,
    );

    instance.setCustomRenderers({
      CommentAvatar: ({ comment }) => {
        let commentAvatar = commentAvatars[comment.id];

        // Cache avatars so that they are not recreated on every update.
        if (!commentAvatar) {
          let userAvatarTemplate = userAvatarTemplates[comment.creatorName];

          // This is a template avatar image for a specific creatorName.
          // In a real world application you might want to cache by a userId.
          if (!userAvatarTemplate) {
            userAvatarTemplate = document.createElement("img");
            userAvatarTemplate.src = "/static/avatar.png";
            userAvatarTemplates[comment.creatorName] = userAvatarTemplate;
          }

          userAvatarTemplate.style.width = "32px";
          userAvatarTemplate.style.borderRadius = "50%";

          // Every comment needs its own image element even though the image
          // belongs to the same user - that's why we clone the template.
          commentAvatar = userAvatarTemplate.cloneNode();
          commentAvatars[comment.id] = commentAvatar;
        }

        return {
          node: commentAvatar,
          append: false,
        };
      },
    });

    return instance;
  });
}

/**
 * This section is not relevant for the demo. This is just a UI implementation of message that we show
 * if the user is running the standalone setup in our catalog examples to tell the user that
 * we don't support this feature in standalone mode. You can ignore this.
 */
export const CustomContainer = React.forwardRef((props, ref) => {
  React.useEffect(() => {
    if (!isInstant) return;

    const creator = window.prompt(
      "Choose a user name for commenting. By setting the username to 'Admin' you can edit all the comments.",
    );

    const finalCreatorName = creator || defaultCreatorName();

    window.jwtParameters = { user_id: finalCreatorName };

    // Re-render the document with the updated user ID.
    props.onForceReRender();
  }, [props.onForceReRender]);

  return <div className="container" ref={ref} style={{ height: "100%" }} />;
});

function defaultCreatorName() {
  `Anonymous_${parseInt(Math.random() * 10000)}`;
}

```

This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.

---

## Related pages

- [Add electronic signature images to PDFs using JavaScript](/guides/web/samples/adding-image-electronic-signatures.md)
- [Open, view, and annotate on images using JavaScript](/guides/web/samples/annotating-images.md)
- [Customize PDF annotation permissions using JavaScript](/guides/web/samples/custom-annotation-permissions.md)
- [Customize PDF annotation tooltips using JavaScript](/guides/web/samples/custom-annotation-tooltip.md)
- [Add watermarks to PDFs using JavaScript example](/guides/web/samples/add-watermarks-to-pdf-javascript.md)
- [Customized Document Editor Toolbar](/guides/web/samples/customized-document-editor-toolbar.md)
- [Custom HTML PDF annotations using JavaScript](/guides/web/samples/custom-annotations.md)
- [View PDFs in dark mode using JavaScript](/guides/web/samples/dark-mode-pdf-viewer.md)
- [Edit PDFs using JavaScript](/guides/web/samples/edit-pdf-javascript.md)
- [Customizing PDF text search using JavaScript](/guides/web/samples/customized-pdf-search.md)
- [Create custom overlays on PDFs using JavaScript](/guides/web/samples/custom-overlay-items.md)
- [Add electronic signatures to PDFs using JavaScript](/guides/web/samples/electronic-signatures-in-pdf.md)
- [Customize the PDF toolbar using JavaScript](/guides/web/samples/customized-pdf-toolbar.md)
- [Open PDFs using JavaScript](/guides/web/samples/open-pdf-using-javascript.md)
- [PDF form support using JavaScript](/guides/web/samples/javascript-pdf-form.md)
- [Handling password-protected PDFs in our JavaScript viewer](/guides/web/samples/password-protected-pdf.md)
- [PDF presentation mode using JavaScript](/guides/web/samples/presentation-mode.md)
- [Disable PDF editing and annotations](/guides/web/samples/open-read-only-pdf.md)
- [PDF text selection using JavaScript](/guides/web/samples/pdf-text-selection-javascript.md)
- [Zoom example for our JavaScript PDF viewer](/guides/web/samples/zooming.md)
- [Customizing JavaScript PDF printing modes](/guides/web/samples/pdf-printing-modes.md)
- [Storing electronic signatures in the browser using JavaScript](/guides/web/samples/stored-electronic-signatures.md)
- [Flipbook PDF viewer using JavaScript](/guides/web/samples/flipbook.md)
- [JavaScript PDF magazine viewer](/guides/web/samples/javascript-magazine-viewer.md)
- [Hide or reveal area on PDFs using JavaScript](/guides/web/samples/hide-reveal-area-in-pdf.md)
- [PDF annotation in JavaScript](/guides/web/samples/javascript-pdf-annotations.md)
- [Digitally sign a PDF using JavaScript](/guides/web/samples/javascript-digital-signatures.md)
- [PDF Collaboration permissions using JavaScript](/guides/web/samples/collaboration-permissions.md)
- [Drag-and-drop UI in our JavaScript PDF viewer](/guides/web/samples/drag-and-drop.md)
- [Redact PDFs using JavaScript](/guides/web/samples/javascript-pdf-redaction.md)
- [Customize the UI for PDF annotations using JavaScript](/guides/web/samples/annotations-inspector.md)

