React Markdown Editor

A markdown editor with preview, implemented with React.js and TypeScript.
Alternatives To React Markdown Editor
Project NameStarsDownloadsRepos Using ThisPackages Using ThisMost Recent CommitTotal ReleasesLatest ReleaseOpen IssuesLicenseLanguage
Slate27,0873,499923a day ago686August 23, 2022594mitTypeScript
A completely customizable framework for building rich text editors. (Currently in beta.)
Tiptap19,140136a day ago198September 20, 2022242mitTypeScript
The headless editor framework for web artisans.
Awesome Lowcode11,579
14 days ago4cc0-1.0
Oni11,47713 years ago6April 02, 2017518mitTypeScript
Oni: Modern Modal Editing - powered by Neovim
React Page9,186189 days ago304September 21, 20228mitTypeScript
Next-gen, highly customizable content editor for the browser - based on React and written in TypeScript. WYSIWYG on steroids.
Tinacms8,816561a day ago105September 21, 202282otherTypeScript
The Markdown CMS
H5 Dooring7,298
3 months ago29gpl-3.0JavaScript
H5 Page Maker, H5 Editor, LowCode. Make H5 as easy as building blocks. | 让H5制作像搭积木一样简单, 轻松搭建H5页面, H5网站, PC端网站,LowCode平台.
Vditor6,29911172 days ago310August 04, 202279mitTypeScript
♏ 一款浏览器端的 Markdown 编辑器,支持所见即所得(富文本)、即时渲染(类似 Typora)和分屏预览模式。An In-browser Markdown editor, support WYSIWYG (Rich Text), Instant Rendering (Typora-like) and Split View modes.
React Data Grid6,039441206a day ago1,017September 16, 2022155otherTypeScript
Feature-rich and customizable data grid React component
React Draft Wysiwyg6,0317863372 months ago131July 17, 2022695mitJavaScript
A Wysiwyg editor build on top of ReactJS and DraftJS.
Alternatives To React Markdown Editor
Select To Compare

Alternative Project Comparisons

React Markdown Editor logo

Build & Deploy NPM Download npm version

A markdown editor with preview, implemented with React.js and TypeScript.

React Markdown Editor

Migrate from @uiw/react-markdown-editor 4.x to 5.x.


npm i @uiw/react-markdown-editor


Official document demo preview (🇨🇳中国镜像网站)

Basic Usage

import MarkdownEditor from '@uiw/react-markdown-editor';
import React from 'react';
import ReactDOM from 'react-dom';

const Dome = () => (

ReactDOM.render(<Dome />, document.getElementById('app'));

Controlled Usage

Open in CodeSandbox

import React, { useState } from 'react';
import MarkdownEditor from '@uiw/react-markdown-editor';

function App() {
  const [markdown, setMarkdown] = useState("");
  return (
      value="# This is a H1  \n## This is a H2  \n###### This is a H6"
      onChange={(value, viewUpdate) => setMarkdown(value)}

export default App;

Only Markdown Preview

Open in CodeSandbox

This markdown preview sub-component is a direct export @uiw/react-markdown-preview component, API documentation, please check @uiw/react-markdown-preview.

import React from 'react';
import MarkdownEditor from '@uiw/react-markdown-editor';

function App() {
  return (
    <MarkdownEditor.Markdown source="# This is a H1  \n## This is a H2  \n###### This is a H6" />

export default App;

Custom Toolbars

Open in CodeSandbox

import React from "react";
import ReactDOM from "react-dom";
import MarkdownEditor from '@uiw/react-markdown-editor';

const title2 = {
  name: 'title2',
  keyCommand: 'title2',
  button: { 'aria-label': 'Add title text' },
  icon: (
    <svg width="12" height="12" viewBox="0 0 512 512">
      <path fill="currentColor" d="M496 80V48c0-8.837-7.163-16-16-16H320c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h37.621v128H154.379V96H192c8.837 0 16-7.163 16-16V48c0-8.837-7.163-16-16-16H32c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h37.275v320H32c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h160c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-37.621V288H357.62v128H320c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h160c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-37.275V96H480c8.837 0 16-7.163 16-16z" />
  execute: ({ state, view }) => {
    if (!state || !view) return;
    const lineInfo = view.state.doc.lineAt(view.state.selection.main.from);
    let mark = '#';
    const matchMark = lineInfo.text.match(/^#+/)
    if (matchMark && matchMark[0]) {
      const txt = matchMark[0];
      if (txt.length < 6) {
        mark = txt + '#';
    if (mark.length > 6) {
      mark = '#';
    const title = lineInfo.text.replace(/^#+/, '')
      changes: {
        from: lineInfo.from,
        insert: `${mark}${title}`
      // selection: EditorSelection.range(lineInfo.from + mark.length,,
      selection: { anchor: lineInfo.from + mark.length },

const Dome = () => (
    value="Hello Markdown!"
      'bold', 'italic', 'header', title2

export default Dome;

Support Nextjs

Use examples in nextjs.

Open in CodeSandbox #52 #224

npm install next-remove-imports
npm install @uiw/react-markdown-editor
// next.config.js
const removeImports = require('next-remove-imports')();
module.exports = removeImports({});
import dynamic from 'next/dynamic';
import '@uiw/react-markdown-editor/markdown-editor.css';
import '@uiw/react-markdown-preview/markdown.css';

const MarkdownEditor = dynamic(
  () => import("@uiw/react-markdown-editor").then((mod) => mod.default),
  { ssr: false }

function HomePage() {
  return (
      <MarkdownEditor value="Hello Markdown!" />

export default HomePage;

Support dark-mode/night-mode

By default, the dark-mode is automatically switched according to the system. If you need to switch manually, just set the data-color-mode="dark" parameter for html Element.

<html data-color-mode="dark">
document.documentElement.setAttribute('data-color-mode', 'dark')
document.documentElement.setAttribute('data-color-mode', 'light')

Inherit custom color variables by adding .wmde-markdown-var selector.

const Demo = () => {
  return (
      <div className="wmde-markdown-var"> </div>
      <MarkdownEditor value="Hello Markdown!" />


  • value (string) - the raw markdown that will be converted to html (required)
  • visible?: boolean - Shows a preview that will be converted to html.
  • toolbars?: ICommand[] | string[] - Tool display settings.
  • toolbarsMode?: ICommand[] | string[] - Tool display settings.
  • onChange?:function(editor: IInstance, data: CodeMirror.EditorChange, value: string) - called when a change is made
  • onBlur?: function(editor: IInstance, event: Event) - event occurs when an object loses focus
  • previewProps - react-markdown options
import { ReactCodeMirrorProps } from '@uiw/react-codemirror';
export interface IMarkdownEditor extends ReactCodeMirrorProps {
  className?: string;
  prefixCls?: string;
  /** The raw markdown that will be converted to html (**required**) */
  value?: string;
  /** Shows a preview that will be converted to html. */
  visible?: boolean;
  visibleEditor?: boolean;
  /** Override the default preview component */
  renderPreview?: (props: MarkdownPreviewProps, initVisible: boolean) => React.ReactNode;
  /** Preview expanded width @default `50%` */
  previewWidth?: string;
  /** Whether to enable scrolling */
  enableScroll?: boolean;
  /** Tool display settings. */
  toolbars?: Commands[];
  /** The tool on the right shows the settings. */
  toolbarsMode?: Commands[];
  /** Tool display filter settings. */
  toolbarsFilter?: (tool: Commands, idx: number) => boolean;
  /** Toolbar on bottom */
  toolbarBottom?: boolean;
  /** Option to hide the tool bar. */
  hideToolbar?: boolean;
  /** [@uiw/react-markdown-preview]( options */
  previewProps?: MarkdownPreviewProps;
  /** replace the default `extensions` */
  reExtensions?: ReactCodeMirrorProps['extensions'];
import React from 'react';
import { ReactCodeMirrorRef } from '@uiw/react-codemirror';
import { MarkdownPreviewProps, MarkdownPreviewRef } from '@uiw/react-markdown-preview';
export * from '@uiw/react-markdown-preview';
export interface ToolBarProps {
  editor: React.RefObject<ReactCodeMirrorRef>;
  preview: React.RefObject<HTMLDivElement>;
  container: React.RefObject<HTMLDivElement>;
  containerEditor: React.RefObject<HTMLDivElement>;
  editorProps: IMarkdownEditor;
export interface MarkdownEditorRef {
  editor: React.RefObject<ReactCodeMirrorRef> | null;
  preview?: React.RefObject<MarkdownPreviewRef> | null;
export declare type Commands = keyof typeof defaultCommands | ICommand;
export interface IToolBarProps<T = Commands> extends ToolBarProps {
  className?: string;
  editorProps: IMarkdownEditor;
  mode?: boolean;
  prefixCls?: string;
  toolbars?: T[];
  onClick?: (type: string) => void;
declare const MarkdownEditor: MarkdownEditorComponent;
declare type MarkdownEditorComponent = React.FC<React.PropsWithRef<IMarkdownEditor>> & {
  Markdown: typeof MarkdownPreview;
export default MarkdownEditor;
import { ReactCodeMirrorRef } from '@uiw/react-codemirror';
import { MarkdownPreviewProps, MarkdownPreviewRef } from '@uiw/react-markdown-preview';
export declare type ButtonHandle = (command: ICommand, props: IMarkdownEditor, options: ToolBarProps) => JSX.Element;
export declare type ICommand = {
  icon?: React.ReactElement;
  name?: string;
  keyCommand?: string;
  button?: ButtonHandle | React.ButtonHTMLAttributes<HTMLButtonElement>;
  execute?: (editor: ReactCodeMirrorRef) => void;
export declare const defaultCommands: {
  undo: ICommand;
  redo: ICommand;
  bold: ICommand;
  italic: ICommand;
  header: ICommand;
  strike: ICommand;
  underline: ICommand;
  quote: ICommand;
  olist: ICommand;
  ulist: ICommand;
  todo: ICommand;
  link: ICommand;
  image: ICommand;
  code: ICommand;
  codeBlock: ICommand;
  fullscreen: ICommand;
  preview: ICommand;
export declare const getCommands: () => ICommand[];
export declare const getModeCommands: () => ICommand[];
export declare const defaultTheme: import("@codemirror/state").Extension;


npm run watch # Listen create type and .tsx files.
npm run start # Preview code example.

npm run doc



As always, thanks to our amazing contributors!

Made with action-contributors.


Licensed under the MIT License.

Popular Reactjs Projects
Popular Editor Projects
Popular Web User Interface Categories
Related Searches

Get A Weekly Email With Trending Projects For These Categories
No Spam. Unsubscribe easily at any time.
Markdown Editor