Discussions
Review and refine content seamlessly. Use suggestions like this added text or to mark text for removal. Discuss changes using comments on many text segments. You can even have overlapping annotations!
1
100%
Files
'use client';
import * as React from 'react';
import { Plate, usePlateEditor } from 'platejs/react';
import { EditorKit } from '@/components/editor/editor-kit';
import { Editor, EditorContainer } from '@/components/ui/editor';
import { DEMO_VALUES } from './values/demo-values';
export default function Demo({ id }: { id: string }) {
const editor = usePlateEditor({
plugins: EditorKit,
value: DEMO_VALUES[id],
});
return (
<Plate editor={editor}>
<EditorContainer variant="demo">
<Editor />
</EditorContainer>
</Plate>
);
}
Adding and displaying comments within content.
discussion-demo


Features
- User Management: Store and manage user data with avatars and names
- Discussion Threads: Manage discussion data structures with comments
- Current User Tracking: Track the current active user for collaboration
- Data Storage: Pure UI plugin for storing collaboration state
- Selector API: Easy access to user data through plugin selectors
Kit Usage
Installation
The fastest way to add discussion functionality is with the DiscussionKit, which includes the pre-configured discussionPlugin along with its Plate UI components.
'use client';
import type { TComment } from '@/components/ui/comment';
import { createPlatePlugin } from 'platejs/react';
import { BlockDiscussion } from '@/components/ui/block-discussion';
export interface TDiscussion {
id: string;
comments: TComment[];
createdAt: Date;
isResolved: boolean;
userId: string;
documentContent?: string;
}
const discussionsData: TDiscussion[] = [
{
id: 'discussion1',
comments: [
{
id: 'comment1',
contentRich: [
{
children: [
{
text: 'Comments are a great way to provide feedback and discuss changes.',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 600_000),
discussionId: 'discussion1',
isEdited: false,
userId: 'charlie',
},
{
id: 'comment2',
contentRich: [
{
children: [
{
text: 'Agreed! The link to the docs makes it easy to learn more.',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 500_000),
discussionId: 'discussion1',
isEdited: false,
userId: 'bob',
},
],
createdAt: new Date(),
documentContent: 'comments',
isResolved: false,
userId: 'charlie',
},
{
id: 'discussion2',
comments: [
{
id: 'comment1',
contentRich: [
{
children: [
{
text: 'Nice demonstration of overlapping annotations with both comments and suggestions!',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 300_000),
discussionId: 'discussion2',
isEdited: false,
userId: 'bob',
},
{
id: 'comment2',
contentRich: [
{
children: [
{
text: 'This helps users understand how powerful the editor can be.',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 200_000),
discussionId: 'discussion2',
isEdited: false,
userId: 'charlie',
},
],
createdAt: new Date(),
documentContent: 'overlapping',
isResolved: false,
userId: 'bob',
},
];
const avatarUrl = (seed: string) =>
`https://api.dicebear.com/9.x/glass/svg?seed=${seed}`;
const usersData: Record<
string,
{ id: string; avatarUrl: string; name: string; hue?: number }
> = {
alice: {
id: 'alice',
avatarUrl: avatarUrl('alice6'),
name: 'Alice',
},
bob: {
id: 'bob',
avatarUrl: avatarUrl('bob4'),
name: 'Bob',
},
charlie: {
id: 'charlie',
avatarUrl: avatarUrl('charlie2'),
name: 'Charlie',
},
};
// This plugin is purely UI. It's only used to store the discussions and users data
export const discussionPlugin = createPlatePlugin({
key: 'discussion',
options: {
currentUserId: 'alice',
discussions: discussionsData,
users: usersData,
},
})
.configure({
render: { aboveNodes: BlockDiscussion },
})
.extendSelectors(({ getOption }) => ({
currentUser: () => getOption('users')[getOption('currentUserId')],
user: (id: string) => getOption('users')[id],
}));
export const DiscussionKit = [discussionPlugin];
BlockDiscussion: Renders discussion UI above nodes
Add Kit
import { createPlateEditor } from 'platejs/react';
import { DiscussionKit } from '@/components/editor/plugins/discussion-kit';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
...DiscussionKit,
],
});Manual Usage
Installation
pnpm add @platejs/comment @platejs/suggestion
Create Plugin
import { createPlatePlugin } from 'platejs/react';
import { BlockDiscussion } from '@/components/ui/block-discussion';
export interface TDiscussion {
id: string;
comments: TComment[];
createdAt: Date;
isResolved: boolean;
userId: string;
documentContent?: string;
}
const usersData = {
alice: {
id: 'alice',
avatarUrl: 'https://api.dicebear.com/9.x/glass/svg?seed=alice6',
name: 'Alice',
},
bob: {
id: 'bob',
avatarUrl: 'https://api.dicebear.com/9.x/glass/svg?seed=bob4',
name: 'Bob',
},
};
export const discussionPlugin = createPlatePlugin({
key: 'discussion',
options: {
currentUserId: 'alice',
discussions: [],
users: usersData,
},
})
.configure({
render: { aboveNodes: BlockDiscussion },
})
.extendSelectors(({ getOption }) => ({
currentUser: () => getOption('users')[getOption('currentUserId')],
user: (id: string) => getOption('users')[id],
}));options.currentUserId: ID of the current active useroptions.discussions: Array of discussion data structuresoptions.users: Object mapping user IDs to user datarender.aboveNodes: RendersBlockDiscussionabove nodes for discussion UIselectors.currentUser: Gets the current user dataselectors.user: Gets user data by ID
Add Plugin
import { createPlateEditor } from 'platejs/react';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
discussionPlugin,
],
});Plate Plus
Plugins
discussionPlugin
Pure UI plugin for managing collaboration state including users and discussion data.
Selectors
currentUser
Gets the current user data.
user
Gets user data by ID.
Types
TDiscussion
Discussion data structure containing comments and metadata.
UserData
User information structure for collaboration.

