react-lexify
TypeScript icon, indicating that this package has built-in type declarations

1.4.1 • Public • Published

react-lexify

License: MIT Made with Lexical npm version PRs Welcome

A powerful, extensible, and modular rich text editor built with Lexical and React. react-lexify is designed for developers who need a flexible editor that can be easily customized with plugins, collaborative features, and advanced content types.

⚠️ Important Note:
This editor is built on top of Lexical, which is an actively developed and evolving library maintained by Meta. As such, breaking changes or frequent updates may occur in Lexical’s core or plugin APIs.
We are committed to keeping react-lexify in sync with Lexical's latest stable versions and will try to publish updates as soon as possible to maintain compatibility and stability.

Table of Contents

🚀 Features

  • 📝 Rich text and plain text editing
  • 🔌 Plugin-based configuration (use only what you need)
  • 🧩 Modular plugins for mentions, emojis, checklists, tables, and embeds
  • 🔄 Real-time collaborative editing with Yjs + WebSocket
  • 🧠 Slash command autocomplete, AI-style shortcuts, and dynamic inputs
  • 🎨 Embedded drawing support via Excalidraw
  • 📑 Table support with advanced features (resizing, merging, coloring)
  • 🎥 Embed support for YouTube, Twitter, Figma, and more
  • 🔧 Customizable editor theme and plugin behaviors
  • 💬 Comment system support (optional)
  • 💯 Written in TypeScript with full typings for all configs

📦 Installation

npm install react-lexify
# or
yarn add react-lexify
# or
pnpm add react-lexify

Make sure you also have:

npm install react react-dom

⚠️ Important Note

To ensure proper styling of the editor and toolbar, you must import the editor’s CSS file once globally.

🌸 Add the following import in your root file (e.g., index.tsx, _app.tsx, or layout):

import "react-lexify/dist/react-lexify.css";

✅ This is required for the editor to render styles correctly.

🎨 You can customize the look and feel later using the theme and toolbarStyle options.


🛠️ Basic Usage

import React from "react";
import Editor from "react-lexify";

export default function MyEditor() {
  return (
    <Editor
      plugins={{
        richText: true,
        toolbar: true,
        table: { enabled: true },
        mentions: {
          enabled: true,
          renderMentionOption: (mention, selected) => (
            <div style={{ background: selected ? "#eee" : "transparent" }}>
              @{mention.meta?.name || mention.displayName}
            </div>
          ),
        },
        emojis: true,
        autoFocus: true,
      }}
    />
  );
}

Basic Usage for Next.js (with SSR-safe Setup)

To integrate react-lexify into a Next.js App Router project safely (especially with plugins like excalidraw that are not SSR-compatible), use the dynamic() import to load the editor client-side only.

1. EditorShell.tsx – Client Component Wrapper

// components/editor/editor-shell.tsx
"use client";

import { Editor, EditorProps } from "react-lexify";

export default function EditorShell(props: EditorProps) {
  return (
    <div className="w-full max-w-full space-y-2 editor-shell">
      <Editor {...props} />
    </div>
  );
}

2. EditorLoader.tsx – Custom Skeleton Loader (Optional)

// components/editor/editor-loader.tsx
import { Skeleton } from "@/components/ui/skeleton";
import { Loader2 } from "lucide-react";

export const EditorLoader = () => {
  return (
    <div className="relative w-full border rounded-md p-3 min-h-[300px] bg-white shadow-sm">
      <div className="flex items-center gap-1 md:gap-2 lg:gap-3 mb-4 overflow-auto">
        <Skeleton className="hidden lg:block h-6 w-6 rounded-full" />
        <Skeleton className="hidden lg:block h-6 w-20" />
        <Skeleton className="hidden lg:block h-6 w-16" />
        <Skeleton className="h-6 w-6" />
        <Skeleton className="h-6 w-6" />
        <Skeleton className="h-6 w-6" />
        <Skeleton className="h-6 w-6" />
        <Skeleton className="hidden lg:block h-6 w-6" />
        <Skeleton className="h-6 w-6" />
        <Skeleton className="h-6 w-6" />
        <Skeleton className="h-6 w-16" />
        <Skeleton className="hidden lg:block h-6 w-16" />
        <Skeleton className="hidden lg:block h-6 w-16" />
        <Skeleton className="hidden lg:block h-6 w-16" />
        <Skeleton className="hidden lg:block h-6 w-10 ml-auto" />
      </div>
      <Skeleton className="h-[280px] w-full rounded-md" />
      <div className="absolute top-1/2 left-1/2 flex flex-col justify-center items-center -translate-x-1/2 -translate-y-1/2">
        <Loader2 className="animate-spin text-muted-foreground" />
        <p className="text-xs font-normal text-muted-foreground mt-2">
          Loading Editor
        </p>
      </div>
    </div>
  );
};

3. Dynamic Import in Page

// app/editor/page.tsx or your dynamic editor page
"use client";

import dynamic from "next/dynamic";
import { EditorLoader } from "@/components/editor/editor-loader";

// Dynamically import EditorShell to disable SSR
const EditorShell = dynamic(() => import("@/components/editor/editor-shell"), {
  ssr: false,
  loading: () => <EditorLoader />,
});

export default function EditorPage() {
  return (
    <div className="p-4">
      <EditorShell
        placeholder="Write your content here..."
        plugins={{
          richText: true,
          toolbar: true,
          history: true,
          excalidraw: true,
        }}
      />
    </div>
  );
}

Why this setup?
Some plugins like Excalidraw or speech-to-text use browser-only APIs and will break on SSR. Using dynamic() with ssr: false ensures these are loaded only on the client.

⚙️ Editor Props

The Editor component accepts the following props:

interface EditorProps {
  initialConfig?: Partial<LexicalComposerInitialConfig>;
  plugins?: EditorPluginConfig;
  placeholder?: string;
  readOnly?: boolean;
  /**
   * @deprecated Use `plugins.mentions.fetchMentions` instead.
   */
  fetchMentions?: (query: string) => Promise<Mention[]>;
  /**
   * @deprecated Use `plugins.mentions.onMentionSelect` instead.
   */
  onMentionSelect?: (mention: Mention) => void;
  /**
   * @deprecated Use `plugins.mentions.renderMentionOption` instead.
   */
  renderMentionOption?: (mention: Mention, isSelected: boolean) => JSX.Element;
  onChange?: (output: EditorState | string) => void;
  outputFormat?: "htmlString" | "editorState";
}
Prop Type Description
initialConfig Partial<LexicalComposerInitialConfig> Partial configuration for the Lexical composer.
plugins EditorPluginConfig Configuration for all plugins. See Plugin Configuration.
placeholder string Placeholder text for the editor when empty.
readOnly boolean Makes the editor read-only when true.
fetchMentions (query: string) => Promise<Mention[]> Deprecated – use plugins.mentions.fetchMentions instead.
onMentionSelect (mention: Mention) => void Deprecated – use plugins.mentions.onMentionSelect instead.
renderMentionOption (mention: Mention, isSelected: boolean) => JSX.Element Deprecated – use plugins.mentions.renderMentionOption instead.
onChange (output: EditorState | string) => void Called whenever the editor content changes. Format is determined by outputFormat.
outputFormat "htmlString" | "editorState" Determines the return format for onChange. Defaults to "htmlString".

⚠️ Deprecated Props (as of v1.0.0)

The following props have been deprecated and will be removed in future versions:

Deprecated Prop Use Instead
fetchMentions plugins.mentions.fetchMentions
onMentionSelect plugins.mentions.onMentionSelect
renderMentionOption plugins.mentions.renderMentionOption

Reason: These props have been scoped under the plugins.mentions object to improve modularity and plugin-specific configuration.

Action: Please migrate to the new structure under plugins.mentions.

🧾 Output Format and Change Handler

You can control what gets returned from the editor via the outputFormat prop and handle the value through onChange prop.

Prop Type Default Description
onChange (output: EditorState | string) => void Called whenever the editor content changes. Depends on outputFormat.
outputFormat "htmlString" | "editorState" "htmlString" Determines the output format passed to onChange.

📤 Output Format Usage

1. HTML String (default)

<Editor
  outputFormat="htmlString"
  onChange={(html) => {
    console.log("HTML content:", html);
  }}
/>

2. Editor State

<Editor
  outputFormat="editorState"
  onChange={(editorState) => {
    console.log("EditorState object:", editorState);
  }}
/>

💡 Tip: Use "htmlString" when rendering or storing HTML; use "editorState" when working with serialized Lexical states (e.g., for collaboration or advanced features).

🔌 Plugin Configuration

The EditorPluginConfig interface defines all available plugin options. Below is a detailed breakdown of each plugin category and available configuration.

Core Plugins

  • autoFocus: boolean - Enables auto-focus on the editor when it mounts. Defaults to false.

    <Editor plugins={{ autoFocus: true }} />
  • clearEditor: boolean - Adds a clear editor button. Defaults to false.

    <Editor plugins={{ clearEditor: true }} />
  • history: boolean - Enables undo/redo history. Defaults to false.

    <Editor plugins={{ history: true }} />
  • selectionAlwaysOnDisplay: boolean - Keeps the selection visible. Defaults to false.

    <Editor plugins={{ selectionAlwaysOnDisplay: true }} />

Rich Text Specific Plugins

  • richText: boolean - Enables rich text editing mode. Required for most rich text features. Defaults to false.
    <Editor plugins={{ richText: true }} />
  • toolbar: boolean - Displays the toolbar. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, toolbar: true }} />
  • shortcuts: boolean - Enables keyboard shortcuts. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, shortcuts: true }} />
  • markdownShortcut: boolean - Enables markdown shortcuts. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, markdownShortcut: true }} />
  • codeHighlight: boolean - Enables code syntax highlighting. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, codeHighlight: true }} />
  • list: boolean - Enables lists (bulleted and numbered). Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, list: true }} />
  • checkList: boolean - Enables checklists. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, checkList: true }} />
  • table: object - Enables tables. Requires richText: true. Defaults to { enabled: false }.
    • enabled: boolean - Enables table functionality.
    • cellMerge: boolean - Enables cell merging.
    • cellBackgroundColor: boolean - Enables cell background color.
    • horizontalScroll: boolean - Enables horizontal scrolling for tables.
    <Editor
      plugins={{
        richText: true,
        table: {
          enabled: true,
          cellMerge: true,
          cellBackgroundColor: true,
          horizontalScroll: true,
        },
      }}
    />
  • tableCellResizer: boolean - Enables table cell resizing. Requires table: { enabled: true }. Defaults to false.
    <Editor
      plugins={{
        richText: true,
        table: { enabled: true },
        tableCellResizer: true,
      }}
    />
  • horizontalRule: boolean - Enables horizontal rules. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, horizontalRule: true }} />
  • tabFocus: boolean - Enables tab focus. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, tabFocus: true }} />
  • tabIndentation: boolean - Enables tab indentation. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, tabIndentation: true }} />

Content Type Plugins

  • images: boolean - Enables image support. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, images: true }} />
  • inlineImage: boolean - Enables inline image support. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, inlineImage: true }} />
  • link: object - Enables link support. Requires richText: true. Defaults to { enabled: false }.
    • enabled: boolean - Enables link functionality.
    • hasAttributes: boolean - Enables link attributes.
    <Editor
      plugins={{ richText: true, link: { enabled: true, hasAttributes: true } }}
    />
  • poll: boolean - Enables poll support. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, poll: true }} />
  • twitter: boolean - Enables Twitter embed support. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, twitter: true }} />
  • youtube: boolean - Enables YouTube embed support. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, youtube: true }} />
  • figma: boolean - Enables Figma embed support. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, figma: true }} />
  • clickableLink: boolean - Enables clickable links. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, clickableLink: true }} />
  • equations: boolean - Enables equation support. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, equations: true }} />
  • excalidraw: boolean - Enables Excalidraw support. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, excalidraw: true }} />
  • collapsible: boolean - Enables collapsible sections. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, collapsible: true }} />
  • pageBreak: boolean - Enables page breaks. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, pageBreak: true }} />
  • layout: boolean - Enables layout features. Requires richText: true. Defaults to false.
    <Editor plugins={{ richText: true, layout: true }} />

Interactive Plugins

  • dragDropPaste: boolean - Enables drag and drop and paste functionality. Defaults to false.

    <Editor plugins={{ dragDropPaste: true }} />
  • componentPicker: boolean - Enables component picker. Defaults to false.

    <Editor plugins={{ componentPicker: true }} />
  • emojiPicker: boolean - Enables emoji picker. Defaults to false.

    <Editor plugins={{ emojiPicker: true }} />
  • autoEmbed: boolean - Enables auto-embedding of links. Defaults to false.

    <Editor plugins={{ autoEmbed: true }} />
  • mentions: object - Enables mentions.

    • enabled: boolean - Enables mentions functionality.
    • fetchMentions: (query: string) => Promise<Mention[]> - Function to fetch mention data.
    • onMentionSelect: (mention: Mention) => void - Callback when a mention is selected.
    • renderMentionOption: (mention: Mention, isSelected: boolean) => JSX.Element - Custom rendering for mention options.
    <Editor
      plugins={{
        mentions: {
          enabled: true,
          fetchMentions: async (query) => {
            // Implement your mention fetching logic here
            const response = await fetch(`/api/users?search=${query}`);
            return response.json();
          },
          onMentionSelect: (mention) => {
            console.log("Mention selected:", mention);
          },
          renderMentionOption: (mention, isSelected) => (
            <div
              style={{
                backgroundColor: isSelected ? "#eee" : "transparent",
                padding: "5px",
              }}
            >
              <div style={{ display: "flex", alignItems: "center" }}>
                <img
                  src={mention.meta.imageUrl || "/default-avatar.png"}
                  style={{
                    width: "24px",
                    height: "24px",
                    borderRadius: "50%",
                    marginRight: "8px",
                  }}
                />
                <div>
                  <div style={{ fontWeight: "bold" }}>{mention.meta.name}</div>
                  <div style={{ fontSize: "12px", color: "#666" }}>
                    {mention.meta.email}
                  </div>
                </div>
              </div>
            </div>
          ),
        },
      }}
    />
  • emojis: boolean - Enables emojis. Defaults to false.

    <Editor plugins={{ emojis: true }} />
  • hashtag: boolean - Enables hashtags. Defaults to false.

    <Editor plugins={{ hashtag: true }} />
  • keywords: boolean - Enables keywords. Defaults to false.

    <Editor plugins={{ keywords: true }} />
  • speechToText: boolean - Enables speech-to-text. Defaults to false.

    <Editor plugins={{ speechToText: true }} />
  • autoLink: boolean - Enables auto-linking. Defaults to false.

    <Editor plugins={{ autoLink: true }} />

Collaborative Editing

  • collaboration: object - Enables collaborative editing.
    • enabled: boolean - Enables collaboration functionality.
    • providerFactory: () => any - Factory function to create a collaboration provider.
    <Editor
      plugins={{
        collaboration: {
          enabled: true,
          providerFactory: () => {
            // Example WebSocket provider setup
            const provider = new WebsocketProvider(
              "wss://your-collaboration-server.com",
              "document-id",
              yourYjsDocument
            );
            return provider;
          },
        },
      }}
    />
  • comment: object - Enables commenting.
    • enabled: boolean - Enables comment functionality.
    • providerFactory: () => any - Factory function to create a comment provider.
    <Editor
      plugins={{
        comment: {
          enabled: true,
          providerFactory: () => {
            // Implement your comment provider factory here
            return {
              addComment: (thread, message) => {
                // Your implementation
              },
              resolveComment: (threadId) => {
                // Your implementation
              },
            };
          },
        },
      }}
    />

UI & Behavior Plugins

  • maxLength: object - Sets a maximum length for the editor content.
    • enabled: boolean - Enables the max length restriction.
    • length: number - The maximum allowed length.
    <Editor plugins={{ maxLength: { enabled: true, length: 200 } }} />
  • characterLimit: object - Sets a character limit for the editor content.
    • enabled: boolean - Enables the character limit.
    • charset: "UTF-8" | "UTF-16" - The character set to use.
    • maxLength: number - The maximum allowed character length.
    <Editor
      plugins={{
        characterLimit: { enabled: true, maxLength: 100, charset: "UTF-8" },
      }}
    />
  • autocomplete: boolean - Enables autocomplete functionality. Defaults to false.
    <Editor plugins={{ autocomplete: true }} />
  • treeView: boolean - Enables a tree view of the editor content. Defaults to false.
    <Editor plugins={{ treeView: true }} />
  • tableOfContents: boolean - Enables a table of contents. Defaults to false.
    <Editor plugins={{ tableOfContents: true }} />
  • contextMenu: boolean - Enables a context menu. Defaults to false.
    <Editor plugins={{ contextMenu: true }} />
  • specialText: boolean - Enables special text handling. Defaults to false.
    <Editor plugins={{ specialText: true }} />
  • actions: object - Enables actions.
    • enabled: boolean - Enables actions functionality.
    • preserveNewLinesInMarkdown: boolean - Preserves new lines in markdown.
    <Editor
      plugins={{ actions: { enabled: true, preserveNewLinesInMarkdown: true } }}
    />

Floating UI Plugins

  • floatingLinkEditor: boolean - Enables the floating link editor. Requires richText: true and link: { enabled: true }. Defaults to false.

    <Editor
      plugins={{
        richText: true,
        link: { enabled: true },
        floatingLinkEditor: true,
      }}
    />
  • floatingTextFormatToolbar: boolean - Enables the floating text format toolbar. Requires richText: true and toolbar: true. Defaults to false.

    <Editor
      plugins={{ richText: true, toolbar: true, floatingTextFormatToolbar: true }}
    />
  • draggableBlock: boolean - Enables draggable blocks. Requires richText: true. Defaults to false.

    <Editor plugins={{ richText: true, draggableBlock: true }} />
  • codeActionMenu: boolean - Enables the code action menu. Requires richText: true and codeHighlight: true. Defaults to false.

    <Editor
      plugins={{ richText: true, codeHighlight: true, codeActionMenu: true }}
    />
  • tableHoverActions: boolean - Enables table hover actions. Requires richText: true and table: { enabled: true }. Defaults to false.

    <Editor
      plugins={{
        richText: true,
        table: { enabled: true },
        tableHoverActions: true,
      }}
    />
  • tableCellActionMenu: boolean - Enables the table cell action menu. Requires richText: true and table: { enabled: true }. Defaults to false.

    <Editor
      plugins={{
        richText: true,
        table: { enabled: true },
        tableCellActionMenu: true,
      }}
    />

🎨 Styling and Class Overrides

react-lexify provides a flexible way to override the default class names used for styling the editor and toolbar components. This allows developers to fully customize the appearance using their own CSS framework (e.g., Tailwind, Bootstrap) or design system.

🎨 Editor Class Overrides

You can override structural wrapper classes using the classOverrides prop. These styles affect how the editor container and internal wrappers are rendered and styled.

<Editor
  classOverrides={{
    editorContainer: "w-full rounded-md border",
    editorScroller: "max-h-[400px] overflow-y-auto",
    editorContent: "min-h-[250px] bg-white px-3 py-2",
    editorShell: "bg-background shadow-sm",
    floatingTextFormatToolbar: {
      container: "flex py-2 px-1 gap-2 h-12",
    },
  }}
/>

🧩 Available Keys for classOverrides

Key Description
editorContainer Outermost wrapper of the editor
editorScroller Scrollable area of the editor
editorContent Core editable content area
editorShell Shell that wraps the editor (for background, border)
floatingTextFormatToolbar Class for the floating text toolbar container
plainText Plain text editor wrapper
richTextPlugin Rich text editor plugin wrapper
treeView Tree view panel if enabled

✅ Use classOverrides for layout-level styling

Editor Theme Customization

<Editor
  initialConfig={{
    theme: {
      paragraph: "my-paragraph-style",
      heading: {
        h1: "text-4xl font-bold",
        h2: "text-3xl font-semibold",
      },
      list: {
        ul: "list-disc pl-5",
        ol: "list-decimal pl-5",
      },
      quote: "border-l-4 pl-4 italic text-muted",
      link: "text-blue-500 underline",
      text: {
        bold: "font-bold",
        italic: "italic",
        underline: "underline",
        strikethrough: "line-through",
      },
    },
  }}
/>

✅ Use initialConfig.theme for formatting nodes like headings, lists, links, etc.

Toolbar Style Customization

You can customize the toolbar in a structured and type-safe way using ToolbarStyleConfig. This supports class overrides and icon or label customization:

ToolbarStyleConfig Properties

Property Type Description
rootClass string | (defaultClass: string) => string Main wrapper class for the toolbar.
buttonClasses Partial<Record<ToolbarButtonKey, string | (defaultClass: string) => string>> Class overrides for each individual button.
iconClasses Partial<Record<ToolbarButtonKey | ToolbarDropdownKey, string | (defaultClass) => string>> Icon-level class override per button or dropdown.
dropdownItemClasses Partial<Record<ToolbarDropdownKey, string | (defaultClass) => string>> Class override for each dropdown item (like h1, bullet list, align options, etc).
labelOverrides Partial<Record<ToolbarDropdownKey, string>> Change default labels shown in dropdowns (e.g., "h1" to "Heading One").

ToolbarButtonKey Descriptions

Key Description
bold Toggle bold text
italic Toggle italic text
underline Toggle underline
code Toggle inline code
link Create or edit a link
strikethrough Toggle strikethrough
subscript Toggle subscript
superscript Toggle superscript
highlight Highlight text
clearFormatting Remove all formatting
undo Undo last action
redo Redo last undone action
insertCodeBlock Insert a code block
insertLink Insert a link
lowercase Transform to lowercase
uppercase Transform to uppercase
capitalize Capitalize text
fontColor Change font color
bgColor Change background color
insert Open insert menu
blockControls Block-level formatting
alignment Align text
fontFamily Change font family
fontSize Change font size
moreStyles Open more styles dropdown
horizontalRule Insert horizontal line
pageBreak Insert page break
image Insert image
inlineImage Insert inline image
gif Insert GIF
excalidraw Insert drawing canvas
table Insert table
poll Insert poll
columns Insert column layout
equation Insert math equation
sticky Insert sticky note
collapsible Insert collapsible section

ToolbarDropdownKey Descriptions

Key Description
paragraph Paragraph text
h1 Heading level 1
h2 Heading level 2
h3 Heading level 3
bullet Bullet list
number Numbered list
check Checklist
quote Blockquote
code Code block
leftAlign Align text left
centerAlign Center align text
rightAlign Align text right
justifyAlign Justify text
startAlign Align to start (for RTL)
endAlign Align to end (for RTL)
outdent Outdent list level
indent Indent list level

Example

<Editor
  plugins={{
    toolbar: true,
  }}
  toolbarStyle={{
    rootClass: "flex gap-2 p-2 bg-white shadow",
    buttonClasses: {
      bold: "text-bold hover:bg-gray-100",
    },
    iconClasses: {
      italic: "text-blue-500",
    },
    dropdownItemClasses: {
      h1: "font-bold text-lg",
    },
    labelOverrides: {
      h1: "Heading One",
      h2: "Heading Two",
    },
  }}
/>

This gives you full flexibility to style, override, or relabel any part of the toolbar to match your design system.

🧩 Advanced Configuration

Full Config Example

Below is a comprehensive example showing most of the available configuration options:

import React from "react";
import Editor from "react-lexify";

export default function FullFeaturedEditor() {
  return (
    <Editor
      placeholder="Write something amazing..."
      initialConfig={{
        namespace: "MyAdvancedEditor",
        theme: {
          // Your custom theme
        },
        onError: (error) => {
          console.error("Editor error:", error);
        },
      }}
      plugins={{
        // Core plugins
        autoFocus: true,
        clearEditor: true,
        history: true,
        selectionAlwaysOnDisplay: true,

        // Rich text plugins
        richText: true,
        toolbar: true,
        shortcuts: true,
        markdownShortcut: true,
        codeHighlight: true,
        list: true,
        checkList: true,

        // Table features
        table: {
          enabled: true,
          cellMerge: true,
          cellBackgroundColor: true,
          horizontalScroll: true,
        },
        tableCellResizer: true,

        // More rich text features
        horizontalRule: true,
        tabFocus: true,
        tabIndentation: true,

        // Content types
        images: true,
        inlineImage: true,
        link: {
          enabled: true,
          hasAttributes: true,
        },
        poll: true,
        twitter: true,
        youtube: true,
        figma: true,
        clickableLink: true,
        equations: true,
        excalidraw: true,
        collapsible: true,
        pageBreak: true,
        layout: true,

        // Interactive plugins
        dragDropPaste: true,
        componentPicker: true,
        emojiPicker: true,
        autoEmbed: true,
        mentions: {
          enabled: true,
          fetchMentions: async (query) => {
            const response = await fetch(`/api/users?search=${query}`);
            return response.json();
          },
        },
        emojis: true,
        hashtag: true,
        keywords: true,
        speechToText: true,
        autoLink: true,

        // Collaborative features
        collaboration: {
          enabled: true,
          providerFactory: () => {
            // Your collaboration provider setup
            return null; // Replace with actual provider
          },
        },
        comment: {
          enabled: true,
          providerFactory: () => {
            // Your comment provider setup
            return null; // Replace with actual provider
          },
        },

        // UI & behavior
        maxLength: {
          enabled: true,
          length: 5000,
        },
        characterLimit: {
          enabled: false,
        },
        autocomplete: true,
        treeView: true,
        tableOfContents: true,
        contextMenu: true,
        specialText: true,
        actions: {
          enabled: true,
          preserveNewLinesInMarkdown: true,
        },

        // Floating UI
        floatingLinkEditor: true,
        floatingTextFormatToolbar: true,
        draggableBlock: true,
        codeActionMenu: true,
        tableHoverActions: true,
        tableCellActionMenu: true,
      }}
    />
  );
}

Mention Type Definition

interface Mention {
  id: string;
  displayName: string;
  meta?: {
    name?: string;
    email?: string;
    imageUrl?: string;
    phoneNumber?: number;
    [key: string]: any; // Additional custom properties
  };
  [key: string]: any; // Any additional top-level properties
}

📝 Examples

Basic Rich Text Editor

import React from "react";
import Editor from "react-lexify";

export default function BasicEditor() {
  return (
    <Editor
      placeholder="Start typing..."
      plugins={{
        richText: true,
        toolbar: true,
        history: true,
        autoFocus: true,
      }}
    />
  );
}

Collaborative Editor

import React from "react";
import Editor from "react-lexify";
import { WebsocketProvider } from "y-websocket";
import * as Y from "yjs";

export default function CollaborativeEditor() {
  const setupCollaboration = () => {
    const doc = new Y.Doc();
    const provider = new WebsocketProvider(
      "wss://your-collaboration-server.com",
      "document-123",
      doc
    );

    return provider;
  };

  return (
    <Editor
      placeholder="Collaborate in real-time..."
      plugins={{
        richText: true,
        toolbar: true,
        history: true,
        collaboration: {
          enabled: true,
          providerFactory: setupCollaboration,
        },
      }}
    />
  );
}

Editor with Social Media Features

import React from "react";
import Editor from "react-lexify";

export default function SocialEditor() {
  return (
    <Editor
      placeholder="What's on your mind?"
      plugins={{
        richText: true,
        toolbar: true,
        mentions: {
          enabled: true,
          fetchMentions: async (query) => {
            // Fetch users from your API
            return [
              {
                id: "1",
                displayName: "John Doe",
                meta: {
                  name: "John",
                  email: "john@example.com",
                  imageUrl: "/john.jpg",
                },
              },
              {
                id: "2",
                displayName: "Jane Smith",
                meta: {
                  name: "Jane",
                  email: "jane@example.com",
                  imageUrl: "/jane.jpg",
                },
              },
            ].filter((user) =>
              user.displayName.toLowerCase().includes(query.toLowerCase())
            );
          },
        },
        hashtag: true,
        emojis: true,
        images: true,
        link: { enabled: true },
        youtube: true,
        twitter: true,
      }}
    />
  );
}

💻 TypeScript Support

The library is built with TypeScript and includes type definitions for all components and configurations:

import { Editor, EditorPluginConfig, Mention } from "react-lexify";

🌐 Browser Support

react-lexify supports all modern browsers:

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License.

Disclaimer: This project (react-lexify) is built on top of Lexical, an open-source framework developed and maintained by Meta Platforms, Inc.. It is an independent project not affiliated with or endorsed by Meta. Portions of the code and plugin structure are adapted from the Lexical Playground, which is also licensed under the MIT License.

👤 Author

by rhythmsapkota GitHub Profile

Contributions, issues, and suggestions are welcome!


Package Sidebar

Install

npm i react-lexify

Weekly Downloads

4

Version

1.4.1

License

MIT

Unpacked Size

6.21 MB

Total Files

109

Last publish

Collaborators

  • rhythmsapkota