You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP β†’
Socket
Book a DemoInstallSign in
Socket

react-lexify

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-lexify

A customizable, performant, and modern rich text editor built with Lexical and React. Created by Rhythm Sapkota.

1.4.1
latest
Source
npmnpm
Version published
Weekly downloads
1
Maintainers
1
Weekly downloads
Β 
Created
Source

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";
}
PropTypeDescription
initialConfigPartial<LexicalComposerInitialConfig>Partial configuration for the Lexical composer.
pluginsEditorPluginConfigConfiguration for all plugins. See Plugin Configuration.
placeholderstringPlaceholder text for the editor when empty.
readOnlybooleanMakes the editor read-only when true.
fetchMentions(query: string) => Promise<Mention[]>Deprecated – use plugins.mentions.fetchMentions instead.
onMentionSelect(mention: Mention) => voidDeprecated – use plugins.mentions.onMentionSelect instead.
renderMentionOption(mention: Mention, isSelected: boolean) => JSX.ElementDeprecated – use plugins.mentions.renderMentionOption instead.
onChange(output: EditorState | string) => voidCalled 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 PropUse Instead
fetchMentionsplugins.mentions.fetchMentions
onMentionSelectplugins.mentions.onMentionSelect
renderMentionOptionplugins.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.

PropTypeDefaultDescription
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

KeyDescription
editorContainerOutermost wrapper of the editor
editorScrollerScrollable area of the editor
editorContentCore editable content area
editorShellShell that wraps the editor (for background, border)
floatingTextFormatToolbarClass for the floating text toolbar container
plainTextPlain text editor wrapper
richTextPluginRich text editor plugin wrapper
treeViewTree 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

PropertyTypeDescription
rootClassstring | (defaultClass: string) => stringMain wrapper class for the toolbar.
buttonClassesPartial<Record<ToolbarButtonKey, string | (defaultClass: string) => string>>Class overrides for each individual button.
iconClassesPartial<Record<ToolbarButtonKey | ToolbarDropdownKey, string | (defaultClass) => string>>Icon-level class override per button or dropdown.
dropdownItemClassesPartial<Record<ToolbarDropdownKey, string | (defaultClass) => string>>Class override for each dropdown item (like h1, bullet list, align options, etc).
labelOverridesPartial<Record<ToolbarDropdownKey, string>>Change default labels shown in dropdowns (e.g., "h1" to "Heading One").

ToolbarButtonKey Descriptions

KeyDescription
boldToggle bold text
italicToggle italic text
underlineToggle underline
codeToggle inline code
linkCreate or edit a link
strikethroughToggle strikethrough
subscriptToggle subscript
superscriptToggle superscript
highlightHighlight text
clearFormattingRemove all formatting
undoUndo last action
redoRedo last undone action
insertCodeBlockInsert a code block
insertLinkInsert a link
lowercaseTransform to lowercase
uppercaseTransform to uppercase
capitalizeCapitalize text
fontColorChange font color
bgColorChange background color
insertOpen insert menu
blockControlsBlock-level formatting
alignmentAlign text
fontFamilyChange font family
fontSizeChange font size
moreStylesOpen more styles dropdown
horizontalRuleInsert horizontal line
pageBreakInsert page break
imageInsert image
inlineImageInsert inline image
gifInsert GIF
excalidrawInsert drawing canvas
tableInsert table
pollInsert poll
columnsInsert column layout
equationInsert math equation
stickyInsert sticky note
collapsibleInsert collapsible section

ToolbarDropdownKey Descriptions

KeyDescription
paragraphParagraph text
h1Heading level 1
h2Heading level 2
h3Heading level 3
bulletBullet list
numberNumbered list
checkChecklist
quoteBlockquote
codeCode block
leftAlignAlign text left
centerAlignCenter align text
rightAlignAlign text right
justifyAlignJustify text
startAlignAlign to start (for RTL)
endAlignAlign to end (for RTL)
outdentOutdent list level
indentIndent 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.

  • Fork the repository
  • Create your feature branch (git checkout -b feature/amazing-feature)
  • Commit your changes (git commit -m 'Add some amazing feature')
  • Push to the branch (git push origin feature/amazing-feature)
  • 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!

Keywords

rich-text-editor

FAQs

Package last updated on 27 May 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts