
Security News
GitHub Actions Checkout Now Blocks Risky pull_request_target Checkouts
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.
fc-react-rich-editor
Advanced tools
An advanced, open-source, 100% customizable rich text editor for React with full TypeScript support
A full-featured, customizable rich text editor for React with TypeScript support. Built on Slate.js.
{{name}}), video embeds (YouTube, Vimeo, etc.)useRichTextEditor hook for full control over renderingnpm install fc-react-rich-editor
Peer dependencies: React 18+ and React DOM.
import { useState } from 'react';
import { RichTextEditor } from 'fc-react-rich-editor';
function App() {
const [value, setValue] = useState([
{ type: 'paragraph', children: [{ text: 'Hello, World!' }] },
]);
return (
<RichTextEditor
value={value}
onChange={setValue}
placeholder="Start writing..."
/>
);
}
Styles are included with the component. For headless usage or custom CSS entry, import explicitly:
import 'fc-react-rich-editor/styles.css';
| Prop | Type | Description |
|---|---|---|
value | Descendant[] | Controlled editor value (Slate JSON) |
defaultValue | Descendant[] | Uncontrolled initial value |
onChange | (value: Descendant[]) => void | Called when content changes |
placeholder | string | Placeholder text |
readOnly | boolean | Read-only mode |
autoFocus | boolean | Focus editor on mount |
minHeight | number | string | Min height of the editable area (e.g. 200 or "20rem") |
className / style | — | Root container class and style |
editorClassName | string | Class on the editable area |
Insert by URL – Use the toolbar image button or context menu; paste an image URL.
Insert by upload – Provide onImageUpload. The editor will show an “Upload” option; your callback uploads the file and returns the image URL.
<RichTextEditor
value={value}
onChange={setValue}
onImageUpload={async (file: File) => {
const formData = new FormData();
formData.append('file', file);
const res = await fetch('/api/upload', { method: 'POST', body: formData });
const { url } = await res.json();
return url; // must return the final image URL
}}
/>
Resize – Select an image; a resize handle appears at the bottom-right corner. Drag to change width (80px–1200px).
Align – When an image is selected, use the alignment bar (left / center / right) below the image.
Use the video button and paste a URL. Supports YouTube, Vimeo, Dailymotion, Loom, Wistia, or direct .mp4 / .webm / .ogg links.
Pass a list of variable names; users can insert them as chips (e.g. {{name}}, {{email}}).
<RichTextEditor
value={value}
onChange={setValue}
variables={['name', 'email', 'company']}
/>
Right-click in the editor to open the context menu for inserting blocks and media. You can add custom commands (e.g. “Callout”, “Divider”) without writing a plugin:
import { Transforms } from 'slate';
import {
RichTextEditor,
type CustomContextMenuCommand,
type SlashMenuConfig,
} from 'fc-react-rich-editor';
const customCommands: CustomContextMenuCommand[] = [
{
id: 'insert-callout',
label: 'Callout',
description: 'Insert a callout box',
category: 'insert',
keywords: ['callout', 'box', 'alert'],
iconPaths: '<rect x="3" y="3" width="18" height="18" rx="2"/>',
action: { type: 'custom', customId: 'insert-callout' },
},
];
const slashConfig: SlashMenuConfig = {
enabled: true,
customCommands,
onContextMenuCommand(customId, editor) {
if (customId === 'insert-callout') {
Transforms.insertNodes(editor, {
type: 'paragraph',
children: [{ text: 'Callout content...' }],
});
}
},
};
<RichTextEditor
value={value}
onChange={setValue}
slashMenu={slashConfig}
/>
toolbar={true} (default), toolbar={false}, or a ToolbarConfig object with groups and items (marks, heading select, link, image, video, variable, table, alignment, etc.).hoveringToolbar={true} (default), hoveringToolbar={false}, or an object to toggle items (bold, italic, link, font color, alignment, etc.) and set order.Override theme tokens via the theme prop:
<RichTextEditor
theme={{
fontFamily: '"Inter", sans-serif',
fontSize: '16px',
focusRingColor: '#3b82f6',
borderRadius: '8px',
toolbarBg: '#f9fafb',
linkColor: '#2563eb',
// ... see RichTextTheme in types
}}
/>
import {
htmlSerializer,
markdownSerializer,
} from 'fc-react-rich-editor';
// Slate value → HTML
const html = htmlSerializer.serialize(value);
// HTML → Slate value
const slateValue = htmlSerializer.deserialize(htmlString);
// Slate value → Markdown
const markdown = markdownSerializer.serialize(value);
You can get HTML or Markdown on every change without calling the serializer yourself:
<RichTextEditor
value={value}
onChange={setValue}
onHTMLChange={(html) => console.log(html)}
onMarkdownChange={(md) => console.log(md)}
/>
Build your own UI around the same editor logic:
import { Slate } from 'slate-react';
import { useRichTextEditor } from 'fc-react-rich-editor';
function MyEditor() {
const { editor, value, onChange, renderElement, renderLeaf } = useRichTextEditor();
return (
<Slate editor={editor} value={value} onChange={onChange}>
<Editable
renderElement={renderElement}
renderLeaf={renderLeaf}
placeholder="Write something..."
/>
</Slate>
);
}
Override how elements or leaves are rendered; return undefined to fall back to the default:
<RichTextEditor
renderElement={({ element, attributes, children }) => {
if (element.type === 'paragraph') {
return <p {...attributes} className="my-paragraph">{children}</p>;
}
return undefined;
}}
renderLeaf={({ leaf, attributes, children }) => {
if (leaf.bold) {
return <strong {...attributes}>{children}</strong>;
}
return undefined;
}}
/>
Pass an array of editor plugins to extend Slate behavior (e.g. custom insertData, isVoid, or new helpers):
import type { EditorPlugin } from 'fc-react-rich-editor';
const withMyFeature: EditorPlugin = (editor) => {
const { insertText } = editor;
editor.insertText = (text) => {
// custom logic
insertText(text);
};
return editor;
};
<RichTextEditor plugins={[withMyFeature]} value={value} onChange={setValue} />
See docs/PLUGINS.md for the full plugin guide and docs/ADDING_FEATURES.md for extending the editor with new features.
You can extend the editor in several ways without forking the package:
| Goal | How |
|---|---|
| New context menu items | Use slashMenu.customCommands and onContextMenuCommand. See Custom commands above and docs/PLUGINS.md. |
| New Slate behavior / node types | Write an editor plugin and pass it in plugins. See docs/PLUGINS.md. |
| Custom block or inline rendering | Use renderElement (and optionally a plugin for isVoid / normalization). See docs/ADDING_FEATURES.md. |
| Custom toolbar / hovering toolbar | Use toolbar and hoveringToolbar config objects. |
| New theme | Use the theme prop. |
For a short “how to add features” guide, see docs/ADDING_FEATURES.md.
The package exports the main component, hooks, serializers, types, and Slate utilities so you don’t need to install slate for basic use:
RichTextEditor, ThemeProvideruseRichTextEditorhtmlSerializer, markdownSerializercreateRichTextEditor, getBlockAlign, setBlockAlign, Transforms (re-export from Slate)Descendant, RichTextEditorProps, EditorPlugin, CustomElement, ImageElement, ImageAlign, ToolbarConfig, SlashMenuConfig, CustomContextMenuCommand, etc.Fahim Mahmud Chisti
MIT
FAQs
An advanced, open-source, 100% customizable rich text editor for React with full TypeScript support
The npm package fc-react-rich-editor receives a total of 37 weekly downloads. As such, fc-react-rich-editor popularity was classified as not popular.
We found that fc-react-rich-editor demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

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.

Security News
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.

Product
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.

Product
Socket MCP now lets AI assistants review org alerts, investigate threats using the Socket threat feed, and inspect package files in addition to dependency scoring.