react-lexify

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
yarn add react-lexify
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
"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)
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
"use client";
import dynamic from "next/dynamic";
import { EditorLoader } from "@/components/editor/editor-loader";
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;
fetchMentions?: (query: string) => Promise<Mention[]>;
onMentionSelect?: (mention: Mention) => void;
renderMentionOption?: (mention: Mention, isSelected: boolean) => JSX.Element;
onChange?: (output: EditorState | string) => void;
outputFormat?: "htmlString" | "editorState";
}
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:
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.
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) => {
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: () => {
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: () => {
return {
addComment: (thread, message) => {
},
resolveComment: (threadId) => {
},
};
},
},
}}
/>
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
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
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
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
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;
};
[key: string]: any;
}
π 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!