WYSIWYG for MDX?! Introducing Vrite's Hybrid Editor
Tags: opensource, webdev, productivity
Published: 2023-10-18 16:01:57

You might be familiar with so-called _What You See Is What You Get_ (WYSIWYG) or _Rich Text_ editors. They’re the core part of popular apps such as Notion, allowing users to both see and edit the formatting and content of the document.

WYSIWYG editors are great for creating all kinds of content but, in some cases, they might be limiting, allowing you to use only a small set of formatting options and elements supported by the editor.

That’s especially problematic in niche content categories, like technical/**developer content**, where content requirements might differ, between companies, teams, and even individual projects.

That’s why formats like **Markdown** (MD) and [MDX](https://mdxjs.com/) (MD with support for JSX) are so popular for use cases like documentation, knowledge bases, or technical blogs. They allow you to use any kind of custom formatting or elements and then process the content for publishing. On top of that, they’re great for implementing a **docs-as-code** approach, where your documentation lives right beside your code (i.e. in a Git repo).

However, writing Markdown files is a very different experience compared to the WYSIWYG approach. It can be challenging for beginners or less technical users, while also getting increasingly difficult to manage as the content base grows. My latest project — [Vrite](https://vrite.io/) — is meant to solve this problem.

## Vrite Hybrid Editor

Vrite is an [open-source](https://github.com/vriteio/vrite/stargazers) developer content platform, featuring extensible editing experience, content management tools, and powerful APIs. It’s intended as an all-in-one, collaborative solution for product documentation, technical blogs, and knowledge bases.

With a collaborative WYSIWYG editor being a core part of the experience, I was [thinking for a long time](https://x.com/areknawo/status/1703836534586151017) about how to create an experience that still has the power and customizability of MDX when needed. That’s how I came up with Vrite’s new [_Hybrid Editor_](https://editor.vrite.io/).

![The Element block in Vrite editor](https://assets.vrite.io/6409e82d7dfc74cef7a72e0d/55R-f3y9j5QmtG3inSChq.png?w=1000)

To be fair, rather than being a whole new editor, in the latest v0.3, the Vrite editor was slightly redesigned and got a new block content type — _Element_ — which enables the use of JSX-like blocks right in the editor, leading to a part-markup, part-WYSIWYG editor.

The Element block can have a _type_ (e.g. `Card`) and a set of _props_ (like `title` or `options`). You can edit it by clicking the opening tag. When the block is active and editable, its syntax will be highlighted.

![Editing Element block in Vrite editor](https://assets.vrite.io/6409e82d7dfc74cef7a72e0d/zRnbx1OOxFxuVBoXflKg7.png?w=1000)

Elements can be either wrappers (containing content) or simple block nodes. You can switch between those two “modes”, similar to how it’s done in JSX/MDX — by changing the closing bracket of the first tag. `/>` is for self-closing, while `>` — for wrapping.

Behind the scenes, Vrite processes the content and makes it accessible in [ProseMirror-based](https://prosemirror.net/) JSON format, including the type and all the props of the Element block.

![JSON content from the Element block.](https://assets.vrite.io/6409e82d7dfc74cef7a72e0d/jLyVtMY9hv75qg4kXU8CW.png)

This format makes it easy to further process the content — whether that’s for use with other features of Vrite or when accessing it through the API for publishing.

## MDX and GitHub Sync

With the Element block enabling the use of more custom content, it also empowers other features of Vrite — such as **Git sync** — with new possibilities.

### Git Sync

When your existing documentation or technical content is stored in MD files in your Git repo, or you want to implement a docs-as-code approach, with your repo being the _single source of truth_ — Git sync allows you to sync the content from your repo with Vrite.

![Vrite Git sync - resolving conflicts](https://assets.vrite.io/6409e82d7dfc74cef7a72e0d/dK6C3rvsjb5YwCKoS0pqb.png)

This way you can still use all of Vrite’s features (e.g. content management, publishing extensions, semantic search, etc.), while also being able to commit your changes to the repo, resolve conflicts, etc. Basically, Git sync turns Vrite into a technical content editor, with additional features on top.

Currently (v0.3.2), Git sync only integrates with **GitHub**, with other providers planned for later on.

![Configuring Vrite's Git sync with GitHub](https://assets.vrite.io/6409e82d7dfc74cef7a72e0d/EmqTRGmXcnypC2UzdcUFA.png)

### Syncing MDX

Git sync works on top of _Input_/_Output Content Transformers_ — functions that can “transform” the content to and from the Vrite’s JSON format and whatever’s in your repo. This is quite versatile, and — in theory — should be able to support all kinds of formats, decoupling the format you use from the tooling and features you have available.

Vrite comes with a [GitHub-Flavored Markdown](https://github.github.com/gfm/) (GFM) transformer built-in. It supports basic Markdown formatting, with the addition of GFM extensions, like task lists or tables.

To extend that, Vrite supports _“remote” transformers_ — essentially processing the content on the backend, communicating via batched `POST` requests.

![Custom transformers section in Vrite's settings](https://assets.vrite.io/6409e82d7dfc74cef7a72e0d/vt9l9iL7Az3AUUJFrI3Ka.png?w=1000)

That’s how the new MDX extension works — it registers a new transformer, that processes your content through endpoints, such as `POST https://extensions.vrite.io/mdx/input`.

![Vrite extensions panel](https://assets.vrite.io/6409e82d7dfc74cef7a72e0d/eAnKI0BAJ1ldf2Te9VR44.png?w=1000)

So, to use Git sync with your MDX content:
1. From the _Extensions_ side panel → Install the MDX extension;
2. From the _Source control_ side panel → Configure GitHub as a provider (selecting your repo and branch, path to sync, and _MDX_ as a transformer; Check out [this blog post](https://vrite.io/blog/notion-like-experience-for-your-git-hub-content/) to learn more on this configuration;
3. After the _Initial sync_, check out your content and verify if it was synced correctly.

### Limitations

The MDX transformer can handle much more than the built-in Markdown transformer:
- It supports YAML frontmatter, with properties like `title`, `description` or `slug` being synced with Vrite’s metadata.
- It supports the Element block, converting it to MDX, as expected.
- It uses a special `<Import>` Element to contain the `import` statements from the MDX file (for better back-and-forth syncing).

That said, with both the Element block and MDX extension being new features in a project that’s still in Beta, there are also some limitations you have to consider:
- For the Element block, you can only use values that are JSON-parseable. So, e.g. passing JSX element as a prop won’t work for now.
- Element is a block and there’s no support for custom inline formatting as of yet. Thus, if you use inline JSX components in your MDX (e.g `<Icon/>`, `<InlineBadge>...</InlineBadge>`, etc.) — they’ll be omitted.
- If you’re extending MDX for custom use cases, the Git sync isn’t guaranteed to work. The MDX transformers support only more popular customizations (such as `title` or metadata for codeblocks);

The end goal with MDX support is to extend the editor to be fully customizable (both inline and block-wise) and provide more documentation and details for users to create custom transformers, to support all kinds of use cases.

## Bottom Line

I fully intend to make Vrite a viable, go-to solution for all developer content needs — one that’s both open-source and extensible, while still providing an integrated, all-in-one experience.

The Element block is an important milestone towards this goal. With custom inline content and an entire extension system — for extending the editor with WYSIWYG components built on top of custom elements — coming soon, there’s still a lot more in store.

If you’re interested in the project, consider [leaving a star on GitHub](https://github.com/vriteio/vrite) 🌟.