diff --git a/.gitignore b/.gitignore
index bad74bfb..8225b310 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,6 @@ node_modules/
.DS_Store
**/dist
**.tgz
-docs
temp
etc
uploads
diff --git a/docs/admonitions.md b/docs/admonitions.md
new file mode 100644
index 00000000..efe93dcf
--- /dev/null
+++ b/docs/admonitions.md
@@ -0,0 +1,55 @@
+---
+title: Admonitions
+slug: Admonitions
+position: 0.815
+---
+
+# Admonitions
+
+Admonitions (also known as callouts or tips) are a common way to highlight some text in a markdown document. [Docusaurus uses them extensively](https://docusaurus.io/docs/markdown-features/admonitions) in its documentation, and provides a pre-made styling (icons, colors, etc).
+
+The admonitions are, in fact, just [conventional container directives](./directives). The MDXEditor package ships a pre-made directive `AdmonitionDirectiveDescriptor` that enables the usage of admonitions in your markdown document.
+
+```tsx
+const admonitionMarkdown = `
+
+:::note
+foo
+:::
+
+:::tip
+Some **content** with _Markdown_ syntax. Check [this component](https://virtuoso.dev/).
+:::
+
+:::info
+Some **content** with _Markdown_ syntax.
+:::
+
+:::caution
+Some **content** with _Markdown_ syntax.
+:::
+
+:::danger
+Some **content** with _Markdown_ syntax.
+:::
+`
+
+
+export const Admonitions: React.FC = () => {
+ return (
+
+ )
+}
+```
diff --git a/docs/basic-formatting.md b/docs/basic-formatting.md
new file mode 100644
index 00000000..3bf9110c
--- /dev/null
+++ b/docs/basic-formatting.md
@@ -0,0 +1,79 @@
+---
+title: Basic Formatting
+slug: basic-formatting
+position: 0.1
+---
+
+# Basic Formatting
+
+In its bare form, MDXEditor supports only the most basic formatting - **bold**, *italic*, underline and `inline code`. It's enough to write a simple text, but not much more. There are several plugins that allow the users to create a document structure and apply semantic formatting.
+
+## Headings
+
+The Headings plugin enables the usage of markdown headings which translate to `H1` - `H6` in HTML.
+
+```tsx
+
+import { MDXEditor } from '@mdxeditor/editor/MDXEditor'
+import { headingsPlugin } from '@mdxeditor/editor/plugins/headings'
+
+//...
+
+```
+
+## Quotes
+
+The Quote plugin enables the usage of quotes which translate to `blockquote` in HTML.
+
+```tsx
+
+import { MDXEditor } from '@mdxeditor/editor/MDXEditor'
+import { quotePlugin } from '@mdxeditor/editor/plugins/quote'
+
+const markdown = "> This is a quote"
+
+//...
+
+```
+
+## Lists
+
+The Lists plugin enables the usage of ordered and unordered lists, including multiple levels of nesting.
+
+```tsx
+
+import { MDXEditor } from '@mdxeditor/editor/MDXEditor'
+import { listsPlugin } from '@mdxeditor/editor/plugins/lists'
+
+const markdown = `
+ * Item 1
+ * Item 2
+ * Item 3
+ * nested item
+
+ 1. Item 1
+ 2. Item 2
+`
+
+//...
+
+```
+
+## Thematic Break
+
+The Thematic Break plugin enables the usage of thematic breaks which translate to `hr` in HTML.
+
+```tsx
+import { MDXEditor } from '@mdxeditor/editor/MDXEditor'
+import { thematicBreakPlugin } from '@mdxeditor/editor/plugins/thematic-break'
+
+const markdown = `
+Hello
+
+---
+
+World
+`
+
+//...
+
diff --git a/docs/code-blocks.md b/docs/code-blocks.md
new file mode 100644
index 00000000..fbad184c
--- /dev/null
+++ b/docs/code-blocks.md
@@ -0,0 +1,139 @@
+---
+title: Code blocks
+slug: code-blocks
+position: 0.6
+---
+
+# Code blocks
+
+The code block plugin enables support for fenced code blocks, but does not include any code editing UI. The `codeMirrorPlugin` and the `sandpackPlugin` build on top of it to provide a code editing experience. The next example enables both plugins along with their respective toolbar components.
+
+```tsx
+const defaultSnippetContent = `
+export default function App() {
+ return (
+
+}
+```
+````
+
+## Configuring the CodeMirror editor
+
+The code mirror editor plugin enables editing of fenced code blocks with basic code editing features like syntax highlighting, indentation and bracket matching. A set of toolbar component utilities support the display of a language selector when the block is in focus, while hiding the rich text editor controls. The plugin accepts supported languages as a parameter option.
+
+## Configuring the Sandpack editor
+
+Compared to the code mirror editor, the Sandpack one is a bit more complex, as Sandpack needs to know the context of the code block in order to execute it correctly. Before diving in, it's good to [understand Sandpack configuration](https://sandpack.codesandbox.io/) itself. MDXEditor supports multiple Sandpack configurations, based on the meta data of the code block. To configure the supported presets, pass a `sandpackConfig` option in the plugin initialization. For more details, refer to the [SandpackConfig interface](../api/editor.sandpackconfig) and the [SandpackPreset interface](../api/editor.sandpackpreset).
+
+## Build a custom code block editor
+
+You can implement your own stack of custom code editors by passing a code block editor descriptor to the `codeBlockPlugin`. The next example uses a plain text textarea to edit the code block content. More details about each of the constructs in the example can be found in the API reference.
+
+```tsx
+const PlainTextCodeEditorDescriptor: CodeBlockEditorDescriptor = {
+ // always use the editor, no matter the language or the meta of the code block
+ match: (language, meta) => true,
+ // You can have multiple editors with different priorities, so that there's a "catch-all" editor (with the lowest priority)
+ priority: 0,
+ // The Editor is a React component
+ Editor: (props) => {
+ const cb = useCodeBlockEditorContext()
+ // stops the proppagation so that the parent lexical editor does not handle certain events.
+ return (
+
e.nativeEvent.stopImmediatePropagation()}>
+
+ )
+ }
+}
+
+/** use markdown with some code blocks */
+const codeBlocksMarkdown = ""
+
+export function CodeBlock() {
+ return (
+
+ )
+}
+```
diff --git a/docs/content-styling.md b/docs/content-styling.md
new file mode 100644
index 00000000..a47bc4d8
--- /dev/null
+++ b/docs/content-styling.md
@@ -0,0 +1,33 @@
+---
+title: Content styling
+slug: content-styling
+position: 1
+---
+
+# Content styling
+
+The MDXEditor component exposes a property called `contentEditableClassName` that you can use to style the content of the editor. This is useful if you want to use a different font family, or change the contents of the various blocks inside.
+
+For best results, ensure that you style the editor using the same CSS classes that you use in your application.
+
+```css
+.prose {
+ font-family: "Inter", sans-serif;
+}
+
+.prose strong {
+ font-weight: 600;
+}
+```
+
+```tsx
+
+```
+
+## Avoiding collisions with the editor UI
+
+In addition to the content itself, the content editable editor area can include editor elements like the table editor dialog cells and buttons, the frontmatter editor, and the code block editor.
+To avoid breaking the look of those, ensure that your selectors are conservative and don't target generic elements like `div`, for example.
diff --git a/docs/custom-directive-editors.md b/docs/custom-directive-editors.md
new file mode 100644
index 00000000..fcae7533
--- /dev/null
+++ b/docs/custom-directive-editors.md
@@ -0,0 +1,136 @@
+---
+title: Directives
+slug: custom-directive-editors
+position: 0.81
+---
+
+# Directives
+
+Markdown supports [custom constructs called directives](https://talk.commonmark.org/t/generic-directives-plugins-syntax/444), which can describe arbitrary content (a popular example of that being YouTube videos).
+
+```md
+This is the syntax for a custom YouTube directive.
+
+::youtube[Video of a cat in a box]{#01ab2cd3efg}
+```
+
+The directive plugin allows you to create custom editors for the various directives in your markdown source. To get started, you can use the bundled `GenericDirectiveEditor`:
+
+```tsx
+
+// markdown with a custom container directive
+const markdown = `
+:::callout
+you better watch out!
+:::
+
+`
+
+const CalloutDirectiveDescriptor: DirectiveDescriptor = {
+ name: 'callout',
+ testNode(node) {
+ return node.name === 'callout'
+ },
+ // set some attribute names to have the editor display a property editor popup.
+ attributes: [],
+ // used by the generic editor to determine whether or not to render a nested editor.
+ hasChildren: true,
+ Editor: GenericDirectiveEditor
+}
+
+export const CalloutEditor: React.FC = () => {
+ return (
+
+ )
+}
+```
+
+If you need something more flexible, implement a custom directive editor. The example below creates a simple wrapper around the `NestedLexicalEditor` component:
+
+```tsx
+const CalloutCustomDirectiveDescriptor: DirectiveDescriptor = {
+ name: 'callout',
+ testNode(node) {
+ return node.name === 'callout'
+ },
+ attributes: [],
+ hasChildren: true,
+ Editor: (props) => {
+ return (
+
+ )
+ }
+}
+```
+
+## Adding custom directive buttons to the toolbar
+
+You can tap into the `directivesPlugin` state management exports to build an UI that inserts a custom directive node in the editor.
+Below you can find an example toolbar dialog button that will insert an YouTube directive based on user input.
+
+```tsx
+const YouTubeButton = () => {
+ // grab the insertDirective action (a.k.a. publisher) from the
+ // state management system of the directivesPlugin
+ const insertDirective = directivesPluginHooks.usePublisher('insertDirective')
+
+ return (
+ {
+ const videoId = new URL(url).searchParams.get('v')
+ if (videoId) {
+ insertDirective({
+ name: 'youtube',
+ type: 'leafDirective',
+ attributes: { id: videoId },
+ children: []
+ } as LeafDirective)
+ } else {
+ alert('Invalid YouTube URL')
+ }
+ }}
+ />
+ )
+}
+
+export const Youtube: React.FC = () => {
+ return (
+ {
+ return
+ }
+ })
+ ]}
+ />
+ )
+}
+```
+
+## Update the directive attributes
+
+The `useMdastNodeUpdater` hook returns a function that allows you to update the directive node attributes.
+You don't need to maintain a local state; the component gets re-rendered with the new mdast node property.
+
+## Rendering custom directives in production
+
+To replicate the custom directives behavior in "read" mode, you can use the [remark-directive](https://github.com/remarkjs/remark-directive) package to render directives up to your requirements.
diff --git a/docs/customizing-toolbar.md b/docs/customizing-toolbar.md
new file mode 100644
index 00000000..4bf670d1
--- /dev/null
+++ b/docs/customizing-toolbar.md
@@ -0,0 +1,148 @@
+---
+title: Toolbar
+slug: customizing-toolbar
+position: 0.2
+---
+
+# Toolbar
+
+MDXEditor includes a toolbar plugin and a set of toolbar components that you can arrange up to your preferences and the features you have enabled. Most toolbar components need their respective plugins to be enabled in order to work correctly. The next example enables a simple toolbar with undo/redo and bold/italic/underline components in it. Following the same pattern, you can add, rearrange, or add custom toolbar components.
+
+Note: Most of the components accept any properties, but some read the configuration parameters of their respective plugins. A notable exception is the DiffSourceToggleWrapper which requires its children to be the toolbar contents.
+
+```tsx
+import '@mdxeditor/editor/style.css'
+import { MDXEditor } from '@mdxeditor/editor/MDXEditor'
+import { UndoRedo } from '@mdxeditor/editor/plugins/toolbar/components/UndoRedo'
+import { BoldItalicUnderlineToggles } from '@mdxeditor/editor/plugins/toolbar/components/BoldItalicUnderlineToggles'
+import { toolbarPlugin } from '@mdxeditor/editor/plugins/toolbar'
+
+function App() {
+ return (
+ ( <> >)
+ })]}
+ />
+ )
+}
+
+export default App
+```
+
+## Built-in toolbar components
+
+The package comes with a set of built-in toolbar components that give access to the capabilities of the editor. Below is a list of the available components and the plugins they require.
+
+### [BlockTypeSelect](../api/editor.blocktypeselect)
+
+A toolbar component that allows the user to change the block type of the current selection. Supports paragraphs, headings and block quotes.
+
+### [BoldItalicUnderlineToggles](../api/editor.bolditalicunderlinetoggles)
+
+A toolbar component that lets the user toggle bold, italic and underline formatting.
+
+### [ChangeAdmonitionType](../api/editor.changeadmonitiontype)
+
+A component that allows the user to change the admonition type of the current selection. For this component to work, you must pass the [AdmonitionDirectiveDescriptor](../api/editor.admonitiondirectivedescriptor) to the directivesPlugindirectiveDescriptors parameter.
+
+### [ChangeCodeMirrorLanguage](../api/editor.changecodemirrorlanguage)
+
+A component that allows the user to change the code block language of the current selection. For this component to work, you must enable the codeMirrorPlugin for the editor. See [ConditionalContents](../api/editor.conditionalcontents) for an example on how to display the dropdown only when a code block is in focus.
+
+### [CodeToggle](../api/editor.codetoggle)
+
+A toolbar component that lets the user toggle code formatting. Use for inline code elements (like variables, methods, etc).
+
+### [CreateLink](../api/editor.createlink)
+
+A toolbar component that opens the link edit dialog. For this component to work, you must include the linkDialogPlugin.
+
+### [DiffSourceToggleWrapper](../api/editor.diffsourcetogglewrapper)
+
+A wrapper element for the toolbar contents that lets the user toggle between rich text, diff and source mode. Put the rich text toolbar contents as children of this component. For this component to work, you must include the diffSourcePlugin.
+
+### [InsertAdmonition](../api/editor.insertadmonition)
+
+A toolbar dropdown button that allows the user to insert admonitions. For this to work, you need to have the directives plugin enabled with the [AdmonitionDirectiveDescriptor](../api/editor.admonitiondirectivedescriptor) configured.
+
+### [InsertCodeBlock](../api/editor.insertcodeblock)
+
+A toolbar button that allows the user to insert a fenced code block. Once the code block is focused, you can construct a special code block toolbar for it, using the [ConditionalContents](../api/editor.conditionalcontents) primitive. See the [ConditionalContents](../api/editor.conditionalcontents) documentation for an example.
+
+### [InsertFrontmatter](../api/editor.insertfrontmatter)
+
+A toolbar button that allows the user to insert a [front-matter](https://jekyllrb.com/docs/front-matter/) editor (if one is not already present). For this to work, you need to have the frontmatterPlugin plugin enabled.
+
+### [InsertImage](../api/editor.insertimage)
+
+A toolbar button that allows the user to insert an image from an URL. For the button to work, you need to have the imagePlugin plugin enabled.
+
+### [InsertSandpack](../api/editor.insertsandpack)
+
+A dropdown button that allows the user to insert a live code block into the editor. The dropdown offers a list of presets that are defined in the sandpack plugin config. For this to work, you need to have the sandpackPlugin installed.
+
+### [InsertTable](../api/editor.inserttable)
+
+A toolbar button that allows the user to insert a table. For this button to work, you need to have the tablePlugin plugin enabled.
+
+### [InsertThematicBreak](../api/editor.insertthematicbreak)
+
+A toolbar button that allows the user to insert a thematic break (rendered as an HR HTML element). For this button to work, you need to have the thematicBreakPlugin plugin enabled.
+
+### [ListsToggle](../api/editor.liststoggle)
+
+A toolbar toggle that allows the user to toggle between bulleted and numbered lists. Pressing the selected button will convert the current list to the other type. Pressing it again will remove the list. For this button to work, you need to have the listsPlugin plugin enabled.
+
+### [ShowSandpackInfo](../api/editor.showsandpackinfo)
+
+A component that displays the focused live code block's name. For this component to work, you must enable the sandpackPlugin for the editor. See [ConditionalContents](../api/editor.conditionalcontents) for an example on how to display the dropdown only when a Sandpack editor is in focus.
+
+### [UndoRedo](../api/editor.undoredo)
+
+A toolbar component that lets the user undo and redo changes in the editor.
+
+
+## Toolbar primitives for custom components
+
+The editor toolbar is a styled wrapper around the Radix UI [Toolbar](https://radix-ui.com/primitives/docs/components/toolbar) component.
+To maintain consistent styling with the existing tools in your own components, you can use the primitives listed below.
+
+### [SingleChoiceToggleGroup](../api/editor.singlechoicetogglegroup)
+
+A toolbar primitive that allows you to build an UI with multiple exclusive toggle groups, like the list type toggle.
+
+### [Separator](../api/editor.separator)
+
+A toolbar primitive that allows you to show a separator between toolbar items. By default, the separator is styled as vertical line.
+
+### [Select](../api/editor.select)
+
+A toolbar primitive you can use to build dropdowns, such as the block type select. See [SelectProps](../api/editor.selectprops) for more details.
+
+### [MultipleChoiceToggleGroup](../api/editor.multiplechoicetogglegroup)
+
+A toolbar primitive that allows you to build an UI with multiple non-exclusive toggle groups, like the bold/italic/underline toggle.
+
+### [DialogButton](../api/editor.dialogbutton)
+
+Use this primitive to create a toolbar button that opens a dialog with a text input, autocomplete suggestions, and a submit button.
+
+See [DialogButtonProps](../api/editor.dialogbuttonprops) for the properties that can be passed to this component.
+
+
+### [ConditionalContents](../api/editor.conditionalcontents)
+
+A toolbar primitive that allows you to show different contents based on the editor that is in focus. Useful for code editors that have different features and don't support rich text formatting.
+
+### [ButtonWithTooltip](../api/editor.buttonwithtooltip)
+
+A toolbar button with a custom toolbar primitive.
+
+### [Button](../api/editor.button)
+
+A toolbar button primitive.
+
+### [ButtonOrDropdownButton](../api/editor.buttonordropdownbutton)
+
+Use this primitive to create a toolbar button that can be either a button or a dropdown, depending on the number of items passed.
diff --git a/docs/diff-source.md b/docs/diff-source.md
new file mode 100644
index 00000000..5dfea1e1
--- /dev/null
+++ b/docs/diff-source.md
@@ -0,0 +1,30 @@
+---
+title: Diff/source mode
+slug: diff-source
+position: 0.7
+---
+
+# Diff/source mode
+
+The diff/source plugin allows the user to switch to editing the markdown source of the document or to compare it to the initial version of the document.
+It's an useful integration if you're building something for power users that are familiar with markdown. The plugin is enabled by the `DiffSourceToggleWrapper` toolbar component.
+
+```tsx
+ (
+
+
+
+ )
+ })
+ ]}
+/>
+```
+
diff --git a/docs/extending-the-editor.md b/docs/extending-the-editor.md
new file mode 100644
index 00000000..a0de3800
--- /dev/null
+++ b/docs/extending-the-editor.md
@@ -0,0 +1,87 @@
+---
+title: Extending the editor
+slug: extending-the-editor
+position: 99
+---
+
+# Extending the editor
+
+MDXEditor code base is built with extensibility in mind. In fact, even the core editor behavior is built as a plugin. In here, we will cover the conceptual design of the codebase without touching on the specifics of the API.
+
+## The state management model
+
+MDXEditor uses a composable, graph-based reactive state management system internally. When initialized, the component creates multiple systems of stateful and stateless observables (called nodes) into a **realm**.
+From there on, the React layer (properties, user input, etc) and the Lexical editor interact with the realm by publishing into certain nodes and or by subscribing to changes in node values.
+
+Each editor plugin can specify a new set of nodes (called **system**) that can optionally interact with the existing set of systems (declared as dependencies). A good (yet not-so-complex) example of [such system is the diff-source plugin](https://github.com/mdx-editor/editor/blob/plugins/src/plugins/diff-source/index.tsx), that interacts with the core system to change the value of the 'markdown' node when the user edits the content in source mode.
+
+## Accessing the state from React
+
+In addition to the plugin function itself, the `realmPlugin` function returns a set of React hooks (conventionally named `certainPluginHooks`) that let you interact with the nodes declared in the plugin system and its dependencies. The hooks return the node values or functions that can publish into certain nodes. The next example is taken from the diff-source plugin Toolbar item:
+
+```tsx
+export const DiffSourceToggleWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
+ // access the viewMode node value
+ const [viewMode] = diffSourcePluginHooks.useEmitterValues('viewMode')
+ // a function that will publish a new value into the viewMode node
+ const changeViewMode = diffSourcePluginHooks.usePublisher('viewMode')
+
+ return (
+ <>
+ {viewMode === 'rich-text' ? (
+ children
+ ) : viewMode === 'diff' ? (
+ Diff mode
+ ) : (
+ Source mode
+ )}
+
+
+ >
+ )
+}
+
+```
+
+In addition to `useEmitterValues` and `usePublisher`, you can also use the `useEmitter` hook that will execute the provided callback when node changes without causing a re-render.
+While using strings for the nodes, the hooks have strict TypeScript typings, so you should be able to get autocompletion of the nodes you can access.
+
+## Markdown / Editor state conversion
+
+In its `init` method a plugin can specify a set of MDAST/Lexical **visitors** that will be used to convert the markdown source into the editor state and vice versa.
+The visitors are plugged into the core system visitors node and then used for processing the markdown input/output.
+The easiest way for you to get a grip of the mechanism is to take a look at the [core plugin visitors](https://github.com/mdx-editor/editor/tree/main/src/plugins/core), that are used to process the basic nodes like paragraphs, bold, italic, etc. The registration of each visitor looks like this (excerpt from the `core` plugin):
+
+```tsx
+// core import visitors
+realm.pubKey('addImportVisitor', MdastRootVisitor)
+realm.pubKey('addImportVisitor', MdastParagraphVisitor)
+realm.pubKey('addImportVisitor', MdastTextVisitor)
+realm.pubKey('addImportVisitor', MdastFormattingVisitor)
+realm.pubKey('addImportVisitor', MdastInlineCodeVisitor)
+
+// core export visitors
+realm.pubKey('addExportVisitor', LexicalRootVisitor)
+realm.pubKey('addExportVisitor', LexicalParagraphVisitor)
+realm.pubKey('addExportVisitor', LexicalTextVisitor)
+realm.pubKey('addExportVisitor', LexicalLinebreakVisitor)
+```
+
+## Interacting with Lexical
+
+The actual rich-text editing experience is built on top of the [Lexical framework](https://lexical.dev) and its node model. In addition to the out-of-the-box nodes (like paragraph, heading, etc), MDXEditor implements a set of custom nodes that are used for the advanced editors (like the table editor, the image editor, and the code block editor).
+
+Lexical is a powerful framework, so understanding its concepts is a challenge on its own. After [the docs themselves](https://lexical.dev/), A good place to start learning by example is the [Lexical playground source code](https://github.com/facebook/lexical/tree/main/packages/lexical-playground).
+
+*Note: Lexical has its own react-based plugin system, which MDXEditor does not use. It is possible to initialize a React-based lexical plugin through the `realmPlugin` function - [here's how this is done in the listsPlugin, for example](https://github.com/mdx-editor/editor/blob/ff717593f32bb76092524006f4a3bd9446b208e8/src/plugins/lists/index.ts#L93-L94)*.
diff --git a/docs/front-matter.md b/docs/front-matter.md
new file mode 100644
index 00000000..26da84fe
--- /dev/null
+++ b/docs/front-matter.md
@@ -0,0 +1,31 @@
+---
+title: Front-matter
+slug: front-matter
+position: 0.99
+---
+
+# Front-matter
+
+The [front-matter](https://jekyllrb.com/docs/front-matter/) plugin enables an key-value form that edits the front-matter contents of the markdown document, while allowing the user to insert new rows.
+
+```tsx
+// you can try a markdown without the front-matter,
+// the `InsertFrontmatter` button from the toolbar will create a new block.
+
+const frontmatterMarkdown = `
+---
+slug: hello-world
+---
+
+this is a cool markdown
+`
+
+export function Frontmatter() {
+ return (
+ })]}
+ />
+ )
+}
+```
diff --git a/docs/getting-started.md b/docs/getting-started.md
new file mode 100644
index 00000000..9ea10b84
--- /dev/null
+++ b/docs/getting-started.md
@@ -0,0 +1,145 @@
+---
+title: Getting started
+slug: getting-started
+position: 0
+---
+
+# Getting started
+
+You've decided to give MDXEditor a try? That's great, because it does not take a lot of effort. While powerful, the component needs little to boot. In this article, we will go through the necessary steps to reach "Hello world" state.
+
+## Installation
+
+To use MDXEditor to your project, install the `@mdxeditor/editor` NPM package in your React project:
+
+```sh
+npm install --save @mdxeditor/editor
+```
+
+## Importing the component
+
+The MDXEditor package definition uses the [exports field](https://nodejs.org/api/packages.html#exports) to define multiple entry points. This ensures that your bundle won't include features you're not using. Notice that for the exports to work correctly, you need to use **TypeScript 5** with `--moduleResolution bundler`. [See the TypeScript documentation for more details](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html#--moduleresolution-bundler).
+
+Following are the specifics below for the most popular React frameworks.
+
+### Next.js (App router)
+
+By default, Next.js uses `--moduleResolution node` setting in `tsconfig.json`. This means that TypeScript does not take the `exports` package.json field into account. Depending on your project, you may try to change it to `node16` or `bundler` so that you can use the named exports, which will optimize your bundle. If this is not possible, you can still use the catch all export point `@mdxeditor/editor`.
+
+
+In addition, we need to ensure that the editor component is used only on the client. Given its purpose, it makes little to no sense to do server processing. To do so, we can use the `dynamic` function from Next.js. This will ensure that the component is only loaded on the client.
+
+```tsx
+// You can use this code in a separate component that's imported in your pages.
+'use client';
+import '@mdxeditor/editor/style.css';
+import dynamic from 'next/dynamic'
+
+export const MDXEditor = dynamic(
+// preferred way
+ () => import('@mdxeditor/editor/MDXEditor').then((mod) => mod.MDXEditor),
+// legacy, larger bundle
+// () => import('@mdxeditor/editor').then((mod) => mod.MDXEditor),
+ { ssr: false }
+)
+```
+
+If you get stuck, check the [MDX editor in Next.js GitHub sample repository for a working example](https://github.com/mdx-editor/mdx-editor-in-next).
+
+### Next.js (Pages router)
+
+Next.js in pages mode seems to choke on the ESM format of the editor and one of its dependencies. To work around that, include the following packages in your transpilation list in next.config.js:
+
+```ts
+/** @type {import('next').NextConfig} */
+const nextConfig = {
+ transpilePackages: ['@mdxeditor/editor', 'react-diff-view'],
+ reactStrictMode: true,
+ webpack: (config) => {
+ // this will override the experiments
+ config.experiments = { ...config.experiments, topLevelAwait: true };
+ // this will just update topLevelAwait property of config.experiments
+ // config.experiments.topLevelAwait = true
+ return config;
+ },
+}
+
+module.exports = nextConfig
+```
+
+Check the [MDX editor in Next.js (pages) GitHub sample repository for a working example](https://github.com/mdx-editor/mdx-editor-in-next-pages) for a working example.
+
+### Vite
+
+MDXEditor "just works" in Vite, assuming that you use a recent version of it. The only thing you need to watch out for is for the imports to come from the specific path rather than the catch-all one, since TypeScript autocompletes both.
+
+Here's a minimal example for App.tsx:
+
+```tsx
+import '@mdxeditor/editor/style.css'
+
+// importing the editor and the plugin from their full paths
+import { MDXEditor } from '@mdxeditor/editor/MDXEditor'
+import { headingsPlugin } from '@mdxeditor/editor/plugins/headings'
+
+function App() {
+ return (
+
+ )
+}
+
+export default App
+```
+
+If you get stuck, check the [MDX editor in Vite GitHub sample repository for a working example](https://github.com/mdx-editor/mdx-editor-in-vite).
+
+
+### Remix
+
+Remix seems [to struggle with ESM-only packages](https://github.com/remix-run/remix/issues/109), like MDXEditor itself and several of its dependencies. To work around that, ensure that you list all problematic modules in the `serverDependenciesToBundle` field.
+Check the working example that uses dynamic imports in the [MDX editor in Remix GitHub sample repository](https://github.com/mdx-editor/mdx-editor-in-remix).
+
+### Create React App
+
+There's nothing specific about the CRA setup. See the [MDX editor in CRA GitHub sample repository for a working example](https://github/com/mdx-editor/mdx-editor-in-cra).
+
+## Basic usage
+
+The MDXEditor component accepts its initial value through the `markdown` property. Notice that the property works like the [textarea `defaultValue`](https://react.dev/reference/react-dom/components/textarea#providing-an-initial-value-for-a-text-area).
+To change the value dynamically, you should use the `setMarkdown` ref method.
+
+To listen for changes of the value of the editor, use the `onChange` callback property. The event is triggered continuously as the user types, so you can use it to update your state.
+
+Alternatively, to obtain the value of the editor, use the `getMarkdown` ref method.
+
+```tsx
+ // construct a ref to the editor
+ const ref = React.useRef(null)
+ return (
+ <>
+
+
+
+ >
+ )
+```
+
+## Next steps
+
+The editor is now working, but it's not very useful. Depending on your use case, you are will most likely need to enable a set of additional features. To ensure that the bundle size stays small, MDXEditor uses a plugin system. As a convention, each plugin is a separate export, so you can import only the ones you need. Below is an example of a few basic plugins being enabled for the editor.
+
+```tsx
+import { MDXEditor } from '@mdxeditor/editor/MDXEditor'
+import { headingsPlugin } from '@mdxeditor/editor/plugins/headings'
+import { listsPlugin } from '@mdxeditor/editor/plugins/lists'
+import { quotePlugin } from '@mdxeditor/editor/plugins/quote'
+import { thematicBreakPlugin } from '@mdxeditor/editor/plugins/thematic-break'
+
+function App() {
+ return (
+
+ )
+}
+```
+
+Follow the links in the sidebar to learn more about each respective capability and the way to enable it.
diff --git a/docs/images.md b/docs/images.md
new file mode 100644
index 00000000..c400862c
--- /dev/null
+++ b/docs/images.md
@@ -0,0 +1,82 @@
+---
+title: Images
+slug: images
+position: 0.4
+---
+
+# Images
+
+The image plugin lets users include images from the web or from their local device. The images are inserted as markdown images. Users can also paste and drop multiple images at once. Optionally, the plugin accepts image URL auto-complete suggestions, and an upload handler that should handle the upload of the pasted and dropped images to a server.
+
+## Inserting images with links
+
+The `InsertImage` toolbar button lets users insert an image from an URL. When the button is clicked, a dialog is shown, where the user can enter the URL of the image. If the plugin is configured with image URL auto-complete suggestions, they will be shown as the user types.
+
+```tsx
+ {
+ return Promise.resolve('https://picsum.photos/200/300')
+ },
+ imageAutocompleteSuggestions: [
+ 'https://picsum.photos/200/300',
+ 'https://picsum.photos/200',
+ ]
+ }),
+ toolbarPlugin({toolbarContents: () => })
+ ]
+ }
+/>
+```
+
+## Pasting and dropping images
+
+The editor handles dropping and pasting images and clipboard contents that contain images. To handle that, you need to upload the image to a location of your choice and return the URL of the uploaded image. This is done through the `imageUploadHandler` parameter of the `imagePlugin`. The parameter accepts a function that receives a `File` object and returns a `Promise` that resolves to the URL of the uploaded image.
+
+```tsx
+async function imageUploadHandler(image: File) {
+ const formData = new FormData()
+ formData.append('image', image)
+ // send the file to your server and return
+ // the URL of the uploaded image in the response
+ const response = await fetch('/uploads/new', {
+ method: 'POST',
+ body: formData
+ })
+ const json = (await response.json()) as { url: string }
+ return json.url
+}
+
+
+```
+
+## Image resizing
+
+The built-in markdown image syntax does not support explicit image dimensions. To work around that, the image plugin resorts to serializing images as `img` tags with `width` and `height` attributes if the user resizes an image or if the markdown input includes an `img` tag with those attributes set.
+
+```tsx
+const markdown = `
+
+Image without dimensions:
+
+![](https://picsum.photos/200/300)
+
+Image with dimensions:
+
+
+`
+
+
+```
diff --git a/docs/jsx.md b/docs/jsx.md
new file mode 100644
index 00000000..081c532e
--- /dev/null
+++ b/docs/jsx.md
@@ -0,0 +1,105 @@
+---
+title: JSX
+slug: jsx
+position: 0.815
+---
+
+# JSX
+
+The jsx plugin allows you to process and associate custom editors with the JSX components in your markdown source - a capability enabled by [MDX](https://mdxjs.com/). The package includes a generic editor component, but you can also create your own custom editors. The next example includes three JSX descriptors and an example of a custom editor that uses the `NestedLexicalEditor` component to edit the markdown contents of a JSX component.
+
+```tsx
+const jsxComponentDescriptors: JsxComponentDescriptor[] = [
+ {
+ name: 'MyLeaf',
+ kind: 'text', // 'text' for inline, 'flow' for block
+ // the source field is used to construct the import statement at the top of the markdown document.
+ // it won't be actually sourced.
+ source: './external',
+ // Used to construc the property popover of the generic editor
+ props: [
+ { name: 'foo', type: 'string' },
+ { name: 'bar', type: 'string' }
+ ],
+ // wether the component has children or not
+ hasChildren: true,
+ Editor: GenericJsxEditor
+ },
+ {
+ name: 'Marker',
+ kind: 'text',
+ source: './external',
+ props: [{ name: 'type', type: 'string' }],
+ hasChildren: false,
+ Editor: () => {
+ return (
+
+ )
+ }
+ },
+ {
+ name: 'BlockNode',
+ kind: 'flow',
+ source: './external',
+ props: [],
+ hasChildren: true,
+ Editor: GenericJsxEditor
+ }
+]
+
+// a toolbar button that will insert a JSX element into the editor.
+const InsertMyLeaf = () => {
+ const insertJsx = jsxPluginHooks.usePublisher('insertJsx')
+ return (
+
+ )
+}
+
+export const Example = () => {
+ return (
+ (
+ <>
+
+ >
+ )
+ })
+ ]}
+ />
+ )
+}
+```
+
+```md
+import { MyLeaf, BlockNode } from './external';
+
+A paragraph with inline jsx component Nested _markdown_ more .
+
+
+ Content *foo*
+
+ more Content
+
+```
diff --git a/docs/links.md b/docs/links.md
new file mode 100644
index 00000000..f4866450
--- /dev/null
+++ b/docs/links.md
@@ -0,0 +1,47 @@
+---
+title: Links
+slug: links
+position: 0.3
+---
+
+# Links
+
+MDXEditor supports markdown links through the links plugin. An additional popover dialog is provided to let the users insert/edit the link.
+
+## The link plugin
+
+To enable the markdown link import, pass the `linkPlugin` to the plugins property of the MDXEditor component.
+
+```tsx
+import { linkPlugin } from '@mdxeditor/editor/plugins/link'
+// ...
+
+
+```
+
+## The link dialog plugin
+
+The link dialog plugin enables a floating popover that appears when the cursor is inside a link, similar to Google docs. The popover allows the user to edit the link and remove it. The popover also supports a keyboard shortcut to open it - `Ctrl+K` on Windows and `Cmd+K` on Mac.
+
+```tsx
+
+```
+
+### Link autocomplete suggestions
+
+The link dialog can auto-suggest a pre-configured set of links to the user. This comes in handy if you're using an editor in a CMS and you can generate a list of links to the pages that are available in the CMS. The links are passed to the plugin as a property.
+
+```tsx
+
+```
diff --git a/docs/live-demo-contents.md b/docs/live-demo-contents.md
new file mode 100644
index 00000000..e248a8b7
--- /dev/null
+++ b/docs/live-demo-contents.md
@@ -0,0 +1,72 @@
+# Welcome
+
+This is a **live demo** of MDXEditor with all default features on.
+
+> The overriding design goal for Markdown’s formatting syntax is to make it as readable as possible.
+> The idea is that a Markdown-formatted document should be publishable as-is, as plain text,
+> without looking like it’s been marked up with tags or formatting instructions.
+
+[— Daring Fireball](https://daringfireball.net/projects/markdown/).
+
+In here, you can find the following markdown elements:
+
+* Headings
+* Lists
+ * Unordered
+ * Ordered
+ * And nested ;)
+* Links
+* Bold/Italic/Underline formatting
+* Tables
+* Code block editors
+* And much more.
+
+The current editor content is styled using the `@tailwindcss/typography` [plugin](https://tailwindcss.com/docs/typography-plugin).
+
+## What can you do here?
+
+This is a great location for you to test how editing markdown feels. If you have an existing markdown source, you can switch to source mode using the toggle group in the top right, paste it in there, and go back to rich text mode.
+
+If you need a few ideas, here's what you can try:
+
+1. Add your own code sample
+2. Change the type of the headings
+3. Insert a table, add a few rows and columns
+4. Switch back to source markdown to see what you're going to get as an output
+5. Test the diff feature to see how the markdown has changed
+6. Add a frontmatter block through the toolbar button
+
+## A code sample
+
+MDXEditor embeds CodeMirror for code editing.
+
+```tsx
+export default function App() {
+ return (
Hello world
)
+}
+```
+
+## A live code example
+
+The block below is a live React component. You can configure multiple live code presets that specify the available npm packages and the default imports. You can also specify a default component that will be rendered in the live code block.
+
+```jsx live
+export default function App() {
+ return (
+
This is a live React component, that's being previewed in codesandbox.
+
Editing it will update the fenced codeblock in the markdown.
+
)
+}
+```
+
+## A table
+
+Play with the table below - add rows, columns, change column alignment. When editing,
+you can navigate the cells with `enter`, `shift+enter`, `tab` and `shift+tab`.
+
+| Item | In Stock | Price |
+| :---------------- | :------: | ----: |
+| Python Hat | True | 23.99 |
+| SQL Hat | True | 23.99 |
+| Codecademy Tee | False | 19.99 |
+| Codecademy Hoodie | False | 42.99 |
diff --git a/docs/markdown-processing.md b/docs/markdown-processing.md
new file mode 100644
index 00000000..e6c48bd5
--- /dev/null
+++ b/docs/markdown-processing.md
@@ -0,0 +1,19 @@
+---
+title: Markdown processing
+slug: markdown-processing
+position: 4
+---
+
+# Markdown processing
+
+When the editor state changes, MDXEditor converts the lexical node tree to a markdown tree. Then, the resulting markdown tree is converted to a markdown string using the [toMarkdown](https://github.com/syntax-tree/mdast-util-to-markdown) utility. This is a great point for you to change stylistic preferences like bullet markers or how whitespace is treated.
+
+To control the options of the `toMarkdown` invocation, pass your preferences through the `toMarkdownOptions` property. Those values get passed to [`options` argument of the `toMarkdown` call](https://github.com/syntax-tree/mdast-util-to-markdown#options).
+
+By default, the MDXEditor uses the following options:
+
+```tsx
+const DEFAULT_MARKDOWN_OPTIONS: ToMarkdownOptions = {
+ listItemIndent: 'one'
+}
+```
diff --git a/docs/markdown-shortcuts.md b/docs/markdown-shortcuts.md
new file mode 100644
index 00000000..4b675263
--- /dev/null
+++ b/docs/markdown-shortcuts.md
@@ -0,0 +1,33 @@
+---
+title: Markdown shortcuts
+slug: markdown-shortcuts
+position: 0.8
+---
+
+# Markdown keyboard shortcuts
+
+The markdown shortcuts plugin enables typing shortcuts (similar to Notion, recently ported to Google docs) that initiate the corresponding markdown blocks.
+Notice that you will need need the corresponding plugins for the markdown blocks to be rendered correctly.
+
+```tsx
+
+```
+
+## Supported shortcuts
+
+- Use one to six `#` characters to create a heading. The number of `#` characters determines the heading level.
+- Use `*` or `-` to create a list item.
+- Use `>` to create a block quote.
+- Select a text and press `Ctrl+B` to make it bold, `Ctrl+I` to make it italic, or `Ctrl+U` to underline it. Use `Cmd` on macOS.
+- With text selected, use `Cmd+K` to open the link dialog.
+- Use `` ` `` to create inline code.
+- Type ```` ```$lang ```` (with `$lang` being any supported language, followed by space) to insert a code block.
diff --git a/docs/overview.md b/docs/overview.md
new file mode 100644
index 00000000..d290bda4
--- /dev/null
+++ b/docs/overview.md
@@ -0,0 +1,35 @@
+---
+title: Overview
+slug: overview
+position: -1
+---
+
+# Overview
+
+MDXEditor is an open-source React component that allows users to author markdown documents in a WYSIWYG manner. The component is tailored specifically to accommodate the markdown syntax constraints, which means that certain "rich" features are not supported. For example, the user cannot change the font size, the color or the font family of the text. Also, there is no intermediate HTML representation of the markdown document. The component accepts and emits markdown as a string.
+
+Markdown content has multiple applications, so the editor component itself is designed with a minimal "core" set of features, with everything else being enabled through plugins, including relatively common features such as headings, quotes, and links.
+
+## Architecture at a glance
+
+The rich text editor engine is built on top of the [Lexical](https://lexical.dev/) editor framework. Unlike other similar solutions, Lexical supports the implementation of complex interactive editors for a specific purpose, like tables, code blocks or even code with live preview.
+
+MDXEditor's markdown processing is built on top of the [MDAST family of packages](https://github.com/syntax-tree/mdast#list-of-utilities). The component implements a bi-directional conversion between the Markdown Abstract Syntax Tree (MDAST) and the Lexical AST by traversing each tree through a set of visitors that convert the constructs from one tree into the other. Depending on their purpose, some MDXEditor plugins extend the conversion by adding additional MDAST and/or Lexical AST visitors, and by adding additional Lexical AST nodes.
+
+Note: MDXEditor uses the `@lexical/markdown` only for the provided markdown shortcuts. The built-in Lexical markdown processing, is fairly limited and does not handle advanced cases like nested lists for example.
+
+## Is MDXEditor the right choice for my case?
+
+It should be, if you plan to use markdown as a persistent format. Which is a good choice in many cases. Markdown is a popular, clean, tool-independent human-readable format that can be rendered using a variety of tools. It is a great choice for documentation, and it is also a good choice for storing content that is meant to be rendered in multiple formats, like HTML, PDF, or even Word documents. The fact that it is clean of presentation-related information makes it easy to change the rendering of the document without affecting the content itself.
+
+Since markdown rendering is so easy, MDXEditor does not need a "read-only" mode like other editors - you can simply render the markdown string in a markdown renderer of your choice ([next-mdx-remote](https://github.com/hashicorp/next-mdx-remote) being just one of the more convenient ones, if you're using React/Next.js).
+
+The default set of plugins available are geared towards technical documentation, but the editor is extensible enough to accommodate other use cases as well. Depending on your use case, you can also write your own plugins to handle certain markdown constructs.
+
+## Help and support
+
+The editor is developed in the open, in the [mdx-editor/editor](https://github.com/mdx-editor/editor) GitHub repository - give the project a star! I would be more than happy to discuss ideas and potential contributions - open an issue or start a discussion in it. You can also reach out to me via [email](mailto:petyo@virtuoso.dev) if you prefer.
+
+## About the author
+
+I've spent most of my professional career working on components for web developers. Another popular project of mine is [react-virtuoso](https://virtuoso.dev), a React component for efficiently rendering large lists and tabular data. You can find me on [Twitter](https://twitter.com/petyosi) and [LinkedIn](https://www.linkedin.com/in/petyosi/).
diff --git a/docs/tables.md b/docs/tables.md
new file mode 100644
index 00000000..4726835c
--- /dev/null
+++ b/docs/tables.md
@@ -0,0 +1,34 @@
+---
+title: Tables
+slug: tables
+position: 0.5
+---
+
+# Tables
+
+The table plugin enables the usage of [GFM markdown tables](https://github.github.com/gfm/#tables-extension-).
+
+
+```tsx
+const markdown = `
+| foo | bar |
+| --- | --- |
+| baz | bim |
+`
+//...
+})
+ ]
+ }
+/>
+```
+
+## The table editor
+
+The table editor allows the user to insert and remove rows and columns and to change the alignment of the columns.
+Each cell can include markdown content like formatting, links, images, etc.
+
+Note: HTML tables are not supported.
diff --git a/docs/theming.md b/docs/theming.md
new file mode 100644
index 00000000..54366d21
--- /dev/null
+++ b/docs/theming.md
@@ -0,0 +1,77 @@
+---
+title: Theming
+slug: theming
+position: 0.999
+---
+
+# Theming
+
+The editor UI (toolbar, dialogs, etc) colors and fonts are defined as CSS variables attached to the editor root element.
+The color variables follow the [Radix semantic aliasing](https://www.radix-ui.com/colors/docs/overview/aliasing#semantic-aliases) convention.
+
+The example below swaps the editor gray/blue colors with tomato/mauve. In addition, assigning the `dark-theme` class to the editor also flips it to dark mode (this is a feature of the Radix colors).
+
+```css
+@import url('@radix-ui/colors/tomatoDark.css');
+@import url('@radix-ui/colors/mauveDark.css');
+
+.dark-editor {
+ --accentBase: var(--tomato1);
+ --accentBgSubtle: var(--tomato2);
+ --accentBg: var(--tomato3);
+ --accentBgHover: var(--tomato4);
+ --accentBgActive: var(--tomato5);
+ --accentLine: var(--tomato6);
+ --accentBorder: var(--tomato7);
+ --accentBorderHover: var(--tomato8);
+ --accentSolid: var(--tomato9);
+ --accentSolidHover: var(--tomato10);
+ --accentText: var(--tomato11);
+ --accentTextContrast: var(--tomato12);
+
+ --baseBase: var(--mauve1);
+ --baseBgSubtle: var(--mauve2);
+ --baseBg: var(--mauve3);
+ --baseBgHover: var(--mauve4);
+ --baseBgActive: var(--mauve5);
+ --baseLine: var(--mauve6);
+ --baseBorder: var(--mauve7);
+ --baseBorderHover: var(--mauve8);
+ --baseSolid: var(--mauve9);
+ --baseSolidHover: var(--mauve10);
+ --baseText: var(--mauve11);
+ --baseTextContrast: var(--mauve12);
+
+ color: var(--baseText);
+ background: var(--baseBg);
+}
+```
+
+```tsx
+export function CustomTheming() {
+ return (
+ }),
+ listsPlugin(),
+ quotePlugin(),
+ headingsPlugin(),
+ linkPlugin(),
+ linkDialogPlugin(),
+ imagePlugin(),
+ tablePlugin(),
+ thematicBreakPlugin(),
+ frontmatterPlugin(),
+ codeBlockPlugin({ defaultCodeBlockLanguage: 'txt' }),
+ sandpackPlugin({ sandpackConfig: virtuosoSampleSandpackConfig }),
+ codeMirrorPlugin({ codeBlockLanguages: { js: 'JavaScript', css: 'CSS', txt: 'text', tsx: 'TypeScript' } }),
+ directivesPlugin({ directiveDescriptors: [YoutubeDirectiveDescriptor, AdmonitionDirectiveDescriptor] }),
+ diffSourcePlugin({ viewMode: 'rich-text', diffMarkdown: 'boo' }),
+ markdownShortcutPlugin()
+ ]}
+ />
+ )
+}
+```