Components
Cursor Overlay

Cursor Overlay

Overlay a cursor indicator for collaborative editing or real-time interaction.

Installation

npx @udecode/plate-ui@latest add cursor-overlay

Examples

Cursor Overlay

Try to drag over text: you will see a black cursor on the drop target: color and other styles are customizable!
'use client';
 
import React, { useRef } from 'react';
import { CommentsProvider } from '@udecode/plate-comments';
import { Plate } from '@udecode/plate-common';
import { ELEMENT_PARAGRAPH } from '@udecode/plate-paragraph';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
 
import { commentsUsers, myUserId } from '@/lib/plate/comments';
import { MENTIONABLES } from '@/lib/plate/mentionables';
import { plugins } from '@/lib/plate/plate-plugins';
import { cn } from '@/lib/utils';
import { CommentsPopover } from '@/components/plate-ui/comments-popover';
import { CursorOverlay } from '@/components/plate-ui/cursor-overlay';
import { Editor } from '@/components/plate-ui/editor';
import { FixedToolbar } from '@/components/plate-ui/fixed-toolbar';
import { FixedToolbarButtons } from '@/components/plate-ui/fixed-toolbar-buttons';
import { FloatingToolbar } from '@/components/plate-ui/floating-toolbar';
import { FloatingToolbarButtons } from '@/components/plate-ui/floating-toolbar-buttons';
import { MentionCombobox } from '@/components/plate-ui/mention-combobox';
 
export default function PlateEditor() {
  const containerRef = useRef(null);
 
  const initialValue = [
    {
      id: '1',
      type: ELEMENT_PARAGRAPH,
      children: [{ text: 'Hello, World!' }],
    },
  ];
 
  return (
    <DndProvider backend={HTML5Backend}>
      <CommentsProvider users={commentsUsers} myUserId={myUserId}>
        <Plate plugins={plugins} initialValue={initialValue}>
          <div
            ref={containerRef}
            className={cn(
              // Block selection
              '[&_.slate-start-area-left]:!w-[64px] [&_.slate-start-area-right]:!w-[64px] [&_.slate-start-area-top]:!h-4'
            )}
          >
            <FixedToolbar>
              <FixedToolbarButtons />
            </FixedToolbar>
 
            <Editor
              className="px-[96px] py-16"
              autoFocus
              focusRing={false}
              variant="ghost"
              size="md"
            />
 
            <FloatingToolbar>
              <FloatingToolbarButtons />
            </FloatingToolbar>
 
            <MentionCombobox items={MENTIONABLES} />
 
            <CommentsPopover />
 
            <CursorOverlay containerRef={containerRef} />
          </div>
        </Plate>
      </CommentsProvider>
    </DndProvider>
  );
}

API

CursorOverlay

useCursorOverlayPositions

Types

export type SelectionRect = {
  width: number;
  height: number;
 
  top: number;
  left: number;
};
 
export type CaretPosition = {
  height: number;
 
  top: number;
  left: number;
};
 
export type CursorState<TCursorData extends UnknownObject = UnknownObject> = {
  key?: any;
  selection: Range | null;
  data?: TCursorData;
};
 
export interface CursorOverlayState<TCursorData extends Record<string, unknown>>
  extends CursorState<TCursorData> {
  caretPosition: CaretPosition | null;
  selectionRects: SelectionRect[];
}
 
export type CursorData = {
  style?: CSSProperties;
  selectionStyle?: CSSProperties;
};