A React-based markdown editor with live preview functionality, implemented with TypeScript.
npx @tessl/cli install tessl/npm-uiw--react-md-editor@4.0.0React MD Editor is a comprehensive React-based markdown editor with live preview functionality, implemented with TypeScript. It provides a rich editing experience based on textarea encapsulation without depending on modern code editors like Monaco or CodeMirror, making it lightweight and highly customizable.
npm install @uiw/react-md-editorMain editor with syntax highlighting:
import MDEditor from "@uiw/react-md-editor";
import "@uiw/react-md-editor/markdown-editor.css";For better performance (no syntax highlighting):
import MDEditor from "@uiw/react-md-editor/nohighlight";
import "@uiw/react-md-editor/markdown-editor.css";Command system:
import { commands } from "@uiw/react-md-editor/commands";
// or
import MDEditor, { commands } from "@uiw/react-md-editor";Individual imports:
import MDEditor, {
commands,
ICommand,
TextAreaCommandOrchestrator,
getCommands,
getExtraCommands
} from "@uiw/react-md-editor";CommonJS:
const MDEditor = require("@uiw/react-md-editor");
require("@uiw/react-md-editor/markdown-editor.css");import React, { useState } from "react";
import MDEditor from "@uiw/react-md-editor";
import "@uiw/react-md-editor/markdown-editor.css";
function App() {
const [value, setValue] = useState("**Hello world!!!**");
return (
<div className="container">
<MDEditor
value={value}
onChange={(val) => setValue(val || "")}
/>
<MDEditor.Markdown source={value} style={{ whiteSpace: 'pre-wrap' }} />
</div>
);
}Advanced usage with custom commands:
import MDEditor, { commands } from "@uiw/react-md-editor";
function EditorWithCustomCommands() {
const [value, setValue] = useState("");
return (
<MDEditor
value={value}
onChange={setValue}
commands={[
commands.bold,
commands.italic,
commands.strikethrough,
commands.hr,
commands.divider,
commands.link,
commands.code,
commands.image
]}
extraCommands={[
commands.codeEdit,
commands.codeLive,
commands.codePreview,
commands.divider,
commands.fullscreen
]}
/>
);
}React MD Editor is built around several key components:
The primary MDEditor React component providing a complete markdown editing experience with toolbar, textarea, and live preview.
declare const MDEditor: React.ForwardedRefComponent<RefMDEditor, MDEditorProps>;
interface MDEditorProps {
value?: string;
onChange?: (value?: string, event?: React.ChangeEvent<HTMLTextAreaElement>, state?: ContextStore) => void;
commands?: ICommand[];
extraCommands?: ICommand[];
preview?: PreviewType;
height?: CSSProperties['height'];
hideToolbar?: boolean;
visibleDragbar?: boolean;
[key: string]: any;
}
interface RefMDEditor extends ContextStore {
textarea?: HTMLTextAreaElement;
container?: HTMLDivElement;
}
type PreviewType = 'live' | 'edit' | 'preview';Comprehensive command system for toolbar actions, text formatting, and editor controls with built-in commands and extensibility for custom commands.
interface ICommand {
name?: string;
keyCommand?: string;
shortcuts?: string;
prefix?: string;
suffix?: string;
execute?: (state: ExecuteState, commands: ICommand[]) => void;
icon?: React.ReactElement;
children?: ICommand[] | ((state: ExecuteState, commands: ICommand[]) => React.ReactElement);
}
declare const commands: {
bold: ICommand;
italic: ICommand;
strikethrough: ICommand;
title: ICommand;
title1: ICommand;
title2: ICommand;
title3: ICommand;
title4: ICommand;
title5: ICommand;
title6: ICommand;
link: ICommand;
quote: ICommand;
code: ICommand;
codeBlock: ICommand;
image: ICommand;
table: ICommand;
hr: ICommand;
unorderedListCommand: ICommand;
orderedListCommand: ICommand;
checkedListCommand: ICommand;
// ... additional commands
};Utility classes and functions for textarea manipulation, text selection, and markdown formatting operations.
declare class TextAreaCommandOrchestrator {
constructor(textArea: HTMLTextAreaElement);
getState(): false | TextState;
executeCommand(command: ICommand, dispatch?: React.Dispatch<ContextStore>, state?: ContextStore, shortcuts?: string): void;
}
declare class TextAreaTextApi {
constructor(textArea: HTMLTextAreaElement);
replaceSelection(text: string): TextState;
setSelectionRange(selection: TextRange): TextState;
}
declare function insertTextAtPosition(input: HTMLTextAreaElement, text: string): void;
declare function selectWord(options: SelectWordOptions): TextRange;
declare function selectLine(textSection: TextSection): TextRange;interface ContextStore {
markdown?: string;
preview?: PreviewType;
height?: CSSProperties['height'];
fullscreen?: boolean;
highlightEnable?: boolean;
commands?: ICommand[];
extraCommands?: ICommand[];
textarea?: HTMLTextAreaElement;
container?: HTMLDivElement;
dispatch?: React.Dispatch<ContextStore>;
}
interface TextState {
text: string;
selectedText: string;
selection: TextRange;
}
interface TextRange {
start: number;
end: number;
}
interface ExecuteState {
command: ICommand;
state?: ContextStore;
textApi: TextAreaTextApi;
dispatch?: React.Dispatch<ContextStore>;
}
interface Statistics {
text: string;
view: number;
length: number;
focus: boolean;
}