Why we developed a code block widget in Miro

Bogdan Zvyagintsev
Miro Engineering
Published in
6 min readJul 25, 2023

Get a behind-the-scenes look at how Miro Engineering implemented the code widget feature in Miro, as well as some of the technical challenges encountered.

What is a code widget?

Miro has all kinds of users who work in all kinds of roles, from product managers and marketers to agile coaches and designers — plus everyone in between. As developers who also use Miro, we knew we needed to support more technical components to improve the developer experience. A code widget was one of the most requested features by developers in the Miro Community, so we knew it was important to deliver.

Our code widget is a code block with a rich editing experience comparable to a native code editor. It has features like syntax highlighting, auto-closing brackets and indentations, various hotkeys, and more.

GIF showing code block widget in action

By giving developers tools like this, we can unblock entirely new ways of collaboration:

  • Pair programming and tech interviews
  • Prototyping, diagraming, and brainstorming
  • Presentations, webinars, and workshops

Context for developing the code block

We first wanted to test some assumptions about the UX and performance of Miro. Once we had a baseline, we could develop our technical approach. The widget may appear simple, but our team still experienced some interesting challenges during its implementation.

Code editing on the web

Code editing in a web environment is not as trivial a task as it may look. Although there are several libraries available, such as highlightjs and prismjs which can provide code highlighting capabilities, they are primarily designed to work with static code. With some tweaks, it’s possible to make it “live” and highlight code as one types it, but it can quickly lead to performance issues, as it needs to colorize the entire code on every key press.

Developers may also want to have advanced features such as auto closing brackets, line wrapping, and auto-indentation. In these cases, you need to use special web-based code editors like Ace, CodeMirror or Monaco, which are capable of parsing and storing the entered code, reacting to changes, and rendering everything in DOM in a more optimized way. This article details the challenges of code editing on the web and why the process is not as simple as just using a textarea and making a code editor out of it.

Understanding widgets in Miro

Miro boards are heavily based on Canvas API. Almost everything visible on the board, except for the user interface on top of the board, is essentially a continuously updated and re-rendered image. Our custom rendering engine consumes HTML with inline styles and draws text by using canvasContext2D API.

When you double-click on a text widget, it enters Edit mode — it hides the canvas-rendered text and puts an HTML-based text editor with the same content in the DOM, seamlessly positioned in place of the original text. This transition is designed to be smooth, so it’s unnoticeable to the end-user. When you finish editing, the HTML output from the editor is sent to the rendering engine, which then draws the updated text onto the canvas.

It’s challenging to create a seamless user experience with consistent transitions between the Edit and View modes.

Character limit

Apart from the architecture with View and Edit modes, we have a limit of 6000 characters for storing text content. For this project, that means we can’t store an HTML string with the highlighted code in the database, because 6000 characters equals around 20 lines of highlighted code, which is incredibly small.

Considered options

The architecture and limitations greatly influenced the research direction and code block system design. We were mainly focused on finding a solution that would allow us to:

  1. Store plain text in the database.
  2. Run an editor with syntax highlighting (Edit mode), that takes plain text as input and output.
  3. Statically highlight the plain text with inline styles for rendering on the canvas (View mode).

A solution like this would mean we can store longer content and highlight it without running the editor (for example, when loading a board). Otherwise it would have significant performance issues for boards with many widgets.

Flow chart describing code block architecture

Option 1: Reuse existing approach — Quill Editor

First, we tried to cut corners and reuse the existing functionality we use for text editing: the Quill editor. It is well-integrated in Miro and has a native plugin for syntax highlighting that uses the highlightjs, so we can use the same standalone library to highlight plain code before rendering (you can try the prototype we developed to test this approach). However, it proved to be quite fragile and has a few disadvantages:

  • Solutions based on syntax highlighting libraries provide minimal editing features
  • Highlight.js, which Quill uses for syntax highlighting, isn’t the best library available
  • Syntax highlighting has a delay, which impairs the user experience
  • Chaotic typing can break the highlighting completely

While it is technically possible to swap out highlight.js for another library, it doesn’t solve the delay and fragile problems because the issue is connected with the Quill architecture itself. Moreover, this solution is not future-proof since the Quill repository is no longer maintained.

Option 2: Use HTML elements and syntax highlighting libraries

By using various approaches based on HTML elements like this one using textarea and highlightjs/prismjs, we can make editable code blocks with real-time syntax highlightiing. So, again we can use these syntax highlighting libraries standalone to highlight code before rendering. Yet while the prototype with this approach looks impressive, it has a few significant drawbacks:

  • Although it works fine for small code blocks, its performance depends on content length
  • Solutions based on syntax highlighting libraries provide minimal editing features
  • HTML elements don’t provide API comparable to Editors, e.g. working with content, cursors, and history and it may require more effort to implement the necessary functionality
  • Lack of more advanced features such as collaboration

Option 3: Integrate a web-based code editor

In the third prototype we used the web-based code editor CodeMirror. The user experience looked good to us and this approach had all the functionality we required:

  • API for static syntax highlighting without running the actual editor
  • Editor API for working with the editor’s content, history and cursors
  • Rich code editing features like auto closing brackets, auto-indentation, line numbers, line-wrapping, and hotkeys
  • Performance doesn’t depend on content length (can handle around 1 million lines of code)
  • The possibility to extend the functionality, for instance adding collaboration, error highlighting, and code suggestions

As the disadvantage of this solution, we can highlight the heavy weight of the editor, which may result in a longer load time. Also, there were two concerns, which might make this initiative quite effort-consuming and risky:

  • There could be unexpected pitfalls in integrating a code editor into Canvas
  • Quill was deeply integrated into the rendering engine, so it might require refactoring or writing the adapter for the code editor

Decision time: The approach we chose

In the end, we wanted to provide as smooth and rich of an editing experience as possible. We also wanted to future-proof our editor in case we want to support longer text (more than 6000 characters) and extend functionality, such as implementing collaboration or code execution.

Considering that both Quill and HTML elements didn’t fully meet our functional requirements, we chose instead to take a risk and invest in integrating a code editor. It has all the desired features out of the box, provides very solid performance and user experience, and offers a lot of extensions.

Do you have ideas or a different approach to implementing a code block widget? Let us know in the comments — we’re interested in what you have to say!

Are you interested in joining our team? Then check out our open positions. Finally, don’t forget to try Miro or the Miro Developer Platform, where you can build apps on top of Miro.

--

--