VS Code Editor (Monaco) with JSX Syntax Highlighting

The Monaco Editor is a fantastic open-source editor that powers VS Code in the browser. The editor comes with a lot of amazing features out-of-the box, but there's a few missing features that we can add to make it even better. In this article, we're going to be focusing on the react editor and adding support for JSX syntax highlighting.

Monaco Missing JSX Syntax Support 🥹

For now, the Monaco editor doesn't come with built-in support for JSX syntax highlighting. Perhaps someday they will add it, but for now we can fill the gap to add support for it.

The Editor

First things first, we need to install the @monaco-editor/react package.

npm install @monaco-editor/react

If you're not familiar with @monaco-editor/react, you can check out the documentation to learn more.

Now that we have the library installed, we can setup a basic React component to render our editor.

import Editor from '@monaco-editor/react'
import { useState } from 'react'

// a simple react component in string format
const reactCode = `import React from 'react';
import ReactDOM from 'react-dom';

function App () {
  return (
    <div>
      <h1>Hello World</h1>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'))`

function CodeEditor() {
  const [value, setValue] = useState(ReactCode)

  return (
    <Editor
      value={value}
      theme="vs-dark"
      defaultLanguage="typescript"
      onChange={(val) => setValue(val)}
    />
  )
}

If you render that component, you'll notice the jsx syntax highlighting is not working. It will look like this:

The div and h1 tags are not being highlighted in the screenshot above.

Adding JSX Syntax Highlighting

Now that we have our editor setup, we have to install a few packages that will extend the editors functionality to enable jsx syntax highlighting. We're going to be using the @babel/traverse, @babel/parser, and monaco-jsx-highlighter packages.

  • @babel/parser will parse the code into an AST.
  • @babel/traverse will traverse the AST of the code and find the JSX elements.
  • monaco-jsx-highlighter will be used to add the JSX syntax highlighting to the editor.
npm i @babel/traverse @babel/parser monaco-jsx-highlighter

Now let's update our editor component to setup the syntax highlighting.

// This function is used to active the JSX syntax highlighting
const activateMonacoJSXHighlighter = async (monacoEditor, monaco) => {
  const { default: traverse } = await import('@babel/traverse')
  const { parse } = await import('@babel/parser')
  const { default: MonacoJSXHighlighter } = await import(
    'monaco-jsx-highlighter'
  )

  const monacoJSXHighlighter = new MonacoJSXHighlighter(
    monaco,
    parse,
    traverse,
    monacoEditor
  )

  monacoJSXHighlighter.highlightOnDidChangeModelContent()
  monacoJSXHighlighter.addJSXCommentCommand()

  return {
    monacoJSXHighlighter,
  }
}

// ...existing code

// Our editor component
function CodeEditor() {
  const [value, setValue] = useState(ReactCode)

  // We need to listen to the editorDidMount event
  // to setup the JSX syntax highlighting
  const handleEditorDidMount = useCallback(async (editor, monaco) => {
    activateMonacoJSXHighlighter(editor, monaco)
  }, [])

  return (
    <Editor
      value={value}
      theme="vs-dark"
      defaultLanguage="typescript"
      onMount={handleEditorDidMount}
      onChange={(val) => setValue(val)}
    />
  )
}

Now if you render the editor, you should see the JSX syntax highlighting working. It should look like this:

Notice the div and h1 tags are now being highlighted.

🎉 Now we have JSX syntax highlighting in our editor