payload-plugin-comments

SkillDev tools

Use this skill for anything involving the payload-plugin-comments Payload CMS plugin. Triggers include: installing payload-plugin-comments, configuring its options, asking what it does, troubleshooting errors, upgrading versions, writing collections or fields that use it, and answering questions about its API. If the user mentions "payload-plugin-comments", "comments plugin", "field-level comments", "document comments", or "@mention" in any Payload CMS context, always use this skill.

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the payload-plugin-comments skill

What this skill tells your AI

The instructions your AI receives, as published by focusreactive/payload-plugins in packages/payload-plugin-comments/.claude/skills/payload-plugin-comments/SKILL.md and read by ahel’s review.

Adds field-level and document-level commenting to the Payload CMS admin UI, with @mention notifications, comment resolution, and multi-tenancy support.

Source: github.com/focusreactive/payload-plugins npm: @focus-reactive/payload-plugin-comments Payload versions: 3.x


Quick Start

1. Installation

pnpm add @focus-reactive/payload-plugin-comments
# or
npm install @focus-reactive/payload-plugin-comments

Peer dependencies: payload ^3.0.0, @payloadcms/ui ^3.0.0. next ^14 || ^15, react ^18 || ^19, react-dom, and @payloadcms/plugin-multi-tenant are optional.

2. Register the plugin

// payload.config.ts
import { buildConfig } from "payload";
import { commentsPlugin } from "@focus-reactive/payload-plugin-comments";

export default buildConfig({
  plugins: [
    commentsPlugin({
      // Optional: customize which field is used as the document title in the UI
      collections: [
        { slug: "pages", titleField: "title" },
        { slug: "products", titleField: "name" },
      ],
    }),
  ],
  // ... rest of your config
});

3. Regenerate the import map

npx payload generate:importmap
# or: pnpm payload generate:importmap / bunx payload generate:importmap

If you skip this step, comment badges, the drawer, and the header button will not appear in the admin UI.

4. SQL adapters only — run a migration

npx payload migrate:create create_comments
npx payload migrate

Skip if you use the MongoDB adapter.

5. Optional: email notifications

RESEND_API_KEY=re_xxxxxxxxxxxx
RESEND_FROM_EMAIL=comments@yourdomain.com

If these are not set, mentions work in the UI but emails are silently skipped.


Configuration Reference

OptionTypeDefaultDescription
enabledbooleantrueEnable/disable the plugin entirely
collectionsCollectionEntry[][]UI metadata per collection (see below)
usernameFieldPathstring"name"Dot-notation path to display name on the users collection
tenantTenantPluginConfig—Multi-tenancy scoping (see below)
overridesCollectionOverrides—Custom access, hooks, or fields for the comments collection
translationsTranslations—Per-locale UI string overrides

CollectionEntry

interface CollectionEntry {
  slug: string; // Collection slug
  titleField?: string; // Field to show as document title in comments UI (default: "id")
}

Important: You do not need to list every collection here. All collections automatically get comment badges. This array only controls UI metadata.

TenantPluginConfig

interface TenantPluginConfig {
  enabled?: boolean; // default: false
  collectionSlug?: string; // tenants collection slug (default: "tenants")
  documentTenantField?: string; // field on documents holding tenant ref (default: "tenant")
}

What the Plugin Adds

  1. comments collection — Hidden from admin sidebar. Stores all comments with fields: documentId, collectionSlug, globalSlug, fieldPath, locale, text, mentions, author, isResolved, resolvedBy, resolvedAt.
  2. Field comment badges — Every labeled field across all collections and globals automatically gets a FieldCommentLabel component injected showing the open comment count. Click to open a comment popup for that field.
  3. Header button — A CommentsHeaderButton is added to the admin header. Opens a global drawer showing all comments across all documents and globals, filterable by open/resolved/mentioned.
  4. Cascade delete — When a document is deleted, all its comments are automatically removed.
  5. @mention autocomplete — Type @ in a comment to mention users. Sends email via Resend.
  6. Comment resolution — Comments can be marked resolved/reopened, recording who resolved them and when.

Usage Patterns

Customising the user display name

If your users collection has the name in a nested field:

commentsPlugin({
  usernameFieldPath: "profile.displayName",
});

Overriding access control

commentsPlugin({
  overrides: {
    access: {
      read: ({ req }) => req.user?.role === "admin",
    },
  },
});

Adding extra fields to the comments collection

commentsPlugin({
  overrides: {
    fields: (defaultFields) => [
      ...defaultFields,
      {
        name: "category",
        type: "select",
        options: ["bug", "suggestion", "question"],
      },
    ],
  },
});

Multi-tenancy integration

Use together with @payloadcms/plugin-multi-tenant:

plugins: [
  multiTenantPlugin({ ... }),
  commentsPlugin({
    tenant: {
      enabled: true,
      collectionSlug: "tenants",
      documentTenantField: "tenant",
    },
  }),
]

Translations

commentsPlugin({
  translations: {
    fr: {
      label: "Commentaires",
      add: "Ajouter un commentaire",
      comment: "Commenter",
      resolve: "Résoudre",
    },
  },
});

Pitfalls

  • Styles must be imported manually — The plugin does not auto-inject CSS. If you forget styles.css, the UI will be unstyled.
  • Import map must be regenerated — Run payload generate:importmap after adding the plugin. Without it, comment badges, the drawer, and the header button will not appear.
  • collections array is optional — Omitting it is valid; comments still work on all collections. The array only sets titleField for the UI.
  • usernameFieldPath must match your users schema — Default is "name". If your users collection stores display names differently, set this explicitly.
  • Email notifications require both env vars — If only one of RESEND_API_KEY / RESEND_FROM_EMAIL is set, emails fail silently with a console error.
  • SQL adapters need a migration — After adding the plugin, run payload migrate:create and payload migrate to create the comments table.

FAQ

Q: Do I need to list every collection in the collections array? A: No. All collections and globals get comment badges automatically. The collections array only adds per-collection UI metadata (titleField).

Q: Can I comment on Payload globals? A: Yes. Globals are supported. Field-level badges are injected into globals the same way as collections.

Q: Where are comments stored? A: In a comments collection that the plugin creates automatically, hidden from the admin sidebar.

Q: How do @mentions work? A: Type @ in the comment editor to trigger an autocomplete dropdown. Selecting a user inserts a @(userId) token. On save, the plugin sends an email via Resend to the mentioned user.

Q: What happens to comments when a document is deleted? A: Comments are cascade-deleted via an afterDelete hook on the parent collection.

Q: Can I filter comments? A: The global header panel supports three filters: Open, Resolved, and Mentioned me.

Further Reading

  • Working examples → ./examples.md

Signals

GitHub stars
21
Last commit
Sep 2026

ahel review

  • K1binfo
    installs-packages

Automated review, not a security audit. Ruleset v1+k2.

Advanced
Item type
skill
Key
payload-plugin-comments
Source
github.com/focusreactive/payload-plugins