Package Exports
- @uiw/react-md-editor
- @uiw/react-md-editor/dist/markdown-editor.css
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@uiw/react-md-editor) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
A simple markdown editor with preview, implemented with React.js and TypeScript. This React Component aims to provide a simple Markdown editor with syntax highlighting support. This is based on textarea
encapsulation, so it does not depend on any modern code editors such as Acs, CodeMirror, Monaco etc.
Features
- 📑 Indent line or selected text by pressing tab key, with customizable indentation.
- ♻️ Based on
textarea
encapsulation, does not depend on any modern code editors. - 🚧 Does not depend on the
uiw
component library. - 🚘 Automatic list on new lines.
- 😻 GitHub flavored markdown support.
- 💡 Support next.js, Use examples in next.js.
Quick Start
npm i @uiw/react-md-editor
Using
import React from "react";
import ReactDOM from "react-dom";
import MDEditor from '@uiw/react-md-editor';
export default function App() {
const [value, setValue] = React.useState("**Hello world!!!**");
return (
<div className="container">
<MDEditor
value={value}
onChange={setValue}
/>
<MDEditor.Markdown source={value} />
</div>
);
}
Custom Toolbars
import React from "react";
import ReactDOM from "react-dom";
import MDEditor, { commands, ICommand, TextState, TextAreaTextApi } from '@uiw/react-md-editor';
const title3: ICommand = {
name: 'title3',
keyCommand: 'title3',
buttonProps: { 'aria-label': 'Insert title3' },
icon: (
<svg width="12" height="12" viewBox="0 0 520 520">
<path fill="currentColor" d="M15.7083333,468 C7.03242448,468 0,462.030833 0,454.666667 L0,421.333333 C0,413.969167 7.03242448,408 15.7083333,408 L361.291667,408 C369.967576,408 377,413.969167 377,421.333333 L377,454.666667 C377,462.030833 369.967576,468 361.291667,468 L15.7083333,468 Z M21.6666667,366 C9.69989583,366 0,359.831861 0,352.222222 L0,317.777778 C0,310.168139 9.69989583,304 21.6666667,304 L498.333333,304 C510.300104,304 520,310.168139 520,317.777778 L520,352.222222 C520,359.831861 510.300104,366 498.333333,366 L21.6666667,366 Z M136.835938,64 L136.835937,126 L107.25,126 L107.25,251 L40.75,251 L40.75,126 L-5.68434189e-14,126 L-5.68434189e-14,64 L136.835938,64 Z M212,64 L212,251 L161.648438,251 L161.648438,64 L212,64 Z M378,64 L378,126 L343.25,126 L343.25,251 L281.75,251 L281.75,126 L238,126 L238,64 L378,64 Z M449.047619,189.550781 L520,189.550781 L520,251 L405,251 L405,64 L449.047619,64 L449.047619,189.550781 Z" />
</svg>
),
execute: (state: TextState, api: TextAreaTextApi) => {
let modifyText = `### ${state.selectedText}\n`;
if (!state.selectedText) {
modifyText = `### `;
}
api.replaceSelection(modifyText);
},
};
export default function App() {
const [value, setValue] = React.useState("**Hello world!!!**");
return (
<div className="container">
<MDEditor
value="Hello Markdown!"
commands={[
// Custom Toolbars
title3,
commands.group([commands.title1, commands.title2, commands.title3, commands.title4, commands.title5, commands.title6], {
name: 'title',
groupName: 'title',
buttonProps: { 'aria-label': 'Insert title'}
}),
commands.divider,
commands.group([], {
name: 'update',
groupName: 'update',
icon: (
<svg viewBox="0 0 1024 1024" width="12" height="12">
<path fill="currentColor" d="M716.8 921.6a51.2 51.2 0 1 1 0 102.4H307.2a51.2 51.2 0 1 1 0-102.4h409.6zM475.8016 382.1568a51.2 51.2 0 0 1 72.3968 0l144.8448 144.8448a51.2 51.2 0 0 1-72.448 72.3968L563.2 541.952V768a51.2 51.2 0 0 1-45.2096 50.8416L512 819.2a51.2 51.2 0 0 1-51.2-51.2v-226.048l-57.3952 57.4464a51.2 51.2 0 0 1-67.584 4.2496l-4.864-4.2496a51.2 51.2 0 0 1 0-72.3968zM512 0c138.6496 0 253.4912 102.144 277.1456 236.288l10.752 0.3072C924.928 242.688 1024 348.0576 1024 476.5696 1024 608.9728 918.8352 716.8 788.48 716.8a51.2 51.2 0 1 1 0-102.4l8.3968-0.256C866.2016 609.6384 921.6 550.0416 921.6 476.5696c0-76.4416-59.904-137.8816-133.12-137.8816h-97.28v-51.2C691.2 184.9856 610.6624 102.4 512 102.4S332.8 184.9856 332.8 287.488v51.2H235.52c-73.216 0-133.12 61.44-133.12 137.8816C102.4 552.96 162.304 614.4 235.52 614.4l5.9904 0.3584A51.2 51.2 0 0 1 235.52 716.8C105.1648 716.8 0 608.9728 0 476.5696c0-132.1984 104.8064-239.872 234.8544-240.2816C258.5088 102.144 373.3504 0 512 0z" />
</svg>
),
children: ({ close, execute, getState, textApi }) => {
return (
<div style={{ width: 120, padding: 10 }}>
<div>My Custom Toolbar</div>
<button type="button" onClick={() => console.log('> execute: >>>>>', getState!())}>State</button>
<button type="button" onClick={() => close()}>Close</button>
<button type="button" onClick={() => execute()}>Execute</button>
</div>
);
},
execute: (state: TextState, api: TextAreaTextApi) => {
console.log('>>>>>>update>>>>>', state)
},
buttonProps: { 'aria-label': 'Insert title'}
}),
]}
/>
</div>
);
}
Preview Markdown
import React from "react";
import ReactDOM from "react-dom";
import MDEditor from '@uiw/react-md-editor';
export default function App() {
return (
<div className="container">
<MDEditor.Markdown source="Hello Markdown!" />
</div>
);
}
Support Custom KaTeX Preview
KaTeX is a fast, easy-to-use JavaScript library for TeX math rendering on the web, We perform math rendering through KaTeX
.
The following example is preview in CodeSandbox.
⚠️ Upgrade v2 to v3 d025430
npm install katex
import React from "react";
import ReactDOM from "react-dom";
import MDEditor from '@uiw/react-md-editor';
import katex from 'katex';
import 'katex/dist/katex.css';
const mdKaTeX = `This is to display the
\`\$\$\c = \\pm\\sqrt{a^2 + b^2}\$\$\`
in one line
\`\`\`KaTeX
c = \\pm\\sqrt{a^2 + b^2}
\`\`\`
`;
export default function App() {
return (
<MDEditor
value={mdKaTeX}
previewOptions={{
components: {
code: ({ inline, children, className, ...props }) => {
const txt = children[0] || '';
if (inline) {
if (typeof txt === 'string' && /^\$\$(.*)\$\$/.test(txt)) {
const html = katex.renderToString(txt.replace(/^\$\$(.*)\$\$/, '$1'), {
throwOnError: false,
});
return <code dangerouslySetInnerHTML={{ __html: html }} />;
}
return <code>{txt}</code>;
}
if (
typeof txt === 'string' &&
typeof className === 'string' &&
/^language-katex/.test(className.toLocaleLowerCase())
) {
const html = katex.renderToString(txt, {
throwOnError: false,
});
return <code dangerouslySetInnerHTML={{ __html: html }} />;
}
return <code className={String(className)}>{txt}</code>;
},
},
}}
/>
);
}
Markdown text to Imgage
import React from "react";
import MDEditor, { commands, ICommand, TextState, TextAreaTextApi } from "@uiw/react-md-editor";
import domToImage from "dom-to-image";
const textToImage: ICommand = {
name: "Text To Image",
keyCommand: "text2image",
buttonProps: { "aria-label": "Insert title3" },
icon: (
<svg width="12" height="12" viewBox="0 0 20 20">
<path fill="currentColor" d="M15 9c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm4-7H1c-.55 0-1 .45-1 1v14c0 .55.45 1 1 1h18c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1zm-1 13l-6-5-2 2-4-5-4 8V4h16v11z" ></path>
</svg>
),
execute: (state: TextState, api: TextAreaTextApi) => {
const dom = document.getElementsByClassName("w-md-editor")[0];
if (dom) {
domToImage.toJpeg(dom, {}).then((dataUrl) => {
const link = document.createElement("a");
link.download = "image.jpg";
link.href = dataUrl;
link.click();
});
}
}
};
export default function App() {
return (
<div className="container">
<MDEditor
value="**Hello world!!!**"
commands={[
textToImage,
commands.divider
]}
/>
</div>
);
}
Support Custom Mermaid Preview
Using mermaid to generation of diagram and flowchart from text in a similar manner as markdown
npm install mermaid
import React from "react";
import ReactDOM from "react-dom";
import MDEditor from "@uiw/react-md-editor";
import mermaid from "mermaid";
const mdMermaid = `The following are some examples of the diagrams, charts and graphs that can be made using Mermaid and the Markdown-inspired text specific to it.
\`\`\`mermaid
graph TD
A[Hard] -->|Text| B(Round)
B --> C{Decision}
C -->|One| D[Result 1]
C -->|Two| E[Result 2]
\`\`\`
\`\`\`mermaid
sequenceDiagram
Alice->>John: Hello John, how are you?
loop Healthcheck
John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts!
John-->>Alice: Great!
John->>Bob: How about you?
Bob-->>John: Jolly good!
\`\`\`
`;
export default function App() {
return (
<MDEditor
height={500}
value={mdMermaid || ""}
previewOptions={{
components: {
code: ({ inline, children, className, ...props }) => {
const txt = children[0] || '';
if (
typeof txt === 'string' &&
typeof className === 'string' &&
/^language-mermaid/.test(className.toLocaleLowerCase())
) {
const Elm = document.createElement("div");
Elm.id = "demo";
const svg = mermaid.render("demo", txt);
return <code dangerouslySetInnerHTML={{ __html: svg }} />
}
return <code className={String(className)}>{txt}</code>;
},
},
}}
/>
);
}
ReactDOM.render(<App />, document.getElementById("container"));
Support Nextjs
Use examples in nextjs.
npm install next-remove-imports
// next.config.js
const removeImports = require('next-remove-imports')();
module.exports = removeImports({});
// pages/index.js
import Head from 'next/head'
import MDEditor from '@uiw/react-md-editor';
import '@uiw/react-md-editor/dist/markdown-editor.css'
import '@uiw/react-markdown-preview/dist/markdown.css';
export default function Home() {
return (
<div>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
</Head>
<MDEditor value="**Hello world!!!**" />
</div>
)
}
Props
value: string
: The Markdown value.onChange?: (value: string)
: Event handler for theonChange
event.commands?: ICommand[]
: An array ofICommand
, which, each one, contain acommands
property. If no commands are specified, the default will be used. Commands are explained in more details below.extraCommands?: ICommand[]
: Displayed on the right side of the toolbar.autoFocus?: true
: Can be used to makeMarkdown Editor
focus itself on initialization.previewOptions?: ReactMarkdown.ReactMarkdownProps
: This is reset @uiw/react-markdown-preview settings.textareaProps?: TextareaHTMLAttributes
: Set thetextarea
related props.height?: number=200
: The height of the editor.visiableDragbar?: boolean=true
: Show drag and drop tool. Set the height of the editor.highlightEnable?: boolean=true
: Disable editing area code highlighting. The value isfalse
, which increases the editing speed.fullscreen?: boolean=false
: Show markdown preview.preview?: 'live' | 'edit' | 'preview'
: Default valuelive
, Show markdown preview.maxHeight?: number=1200
: Maximum drag height. ThevisiableDragbar=true
value is valid.minHeights?: number=100
: Minimum drag height. ThevisiableDragbar=true
value is valid.tabSize?: number=2
: The number of characters to insert when pressing tab key. Default2
spaces.hideToolbar?: boolean=false
: Option to hide the tool bar.enableScroll?: boolean=true
: Whether to enable scrolling.
Development
npm run watch # Listen create type and .tsx files.
npm run css:watch # listen to the component compile and output the .css file
npm run start # Preview code example.
Related
- @uiw/react-md-editor: A simple markdown editor with preview, implemented with React.js and TypeScript.
- @uiw/react-codemirror: CodeMirror component for React. @codemirror
- @uiw/react-monacoeditor: Monaco Editor component for React.
- @uiw/react-markdown-editor: A markdown editor with preview, implemented with React.js and TypeScript.
- @uiw/react-markdown-preview: React component preview markdown text in web browser.
License
Licensed under the MIT License.