Since I started this blog project I've been using a Markdown based WYSIWYG editor. I necessarily had to pick a new framework when I migrated to Vue. Then I found that the new editor I chose was a bit lacking in consistency and overall it was dragging the quality of my codebase down. It didn't support independent styling through variables, instead you had to pick a style and override parts of it. This led to a lot of funky UI bugs that I wasn't a fan of as well as some inconsistency between my editor preview and a published page.
The basics
The start of a Markdown editor is actually pretty simple. I eschewed writing my own lexer and parser because, to me, those are efficiently solved problems. I picked markdown-it because it's fast, extensible, safe, and the API is nice. I created two components: Editor and Previewer. The editor uses the previewer but the previewer can be used independently of the editor for viewing documents.
The major challenge I faced was writing the previewer. I use Tailwind through PrimeVue and Tailwind comes out of the box mostly unstyled. That means that every HTML element that MarkdownIt produces needs to be caught and styled appropriately. To make matters more complex, according to the CommonMark spec some Markdown attributes are derivative of each other (like lists). I landed on an approach that pushes rendering elements into components and those components have derivative components.
Making it shine
Of course, I wouldn't be happy with my editing experience if it didn't shine.
I built the editor with the following features:
- Auto-save on drafts
- A quick select toolbar
- Individual styling of HTML elements
- Side by side editing and preview
- Scroll synchronization across editing and previewing
- Drag and drop file uploads
I'm fairly happy with where things landed. Here's a preview for those interested.