June 01, 2019

(Updated: January 22, 2021)

Adding Codemirror to a React Project

This post is going to cover how to add Codemirror to a react project. Codemirror is a versatile code editor implemeted in javascript for the browser. For my implentation I added it to an electron app built with react but it will work exactly the same in a standard react install. I could have just added the react-codemirror package to do this but sometimes I find adding packages can make things more complicated than they should be.

Okay lets get stuck in!

First we need to npm install codemirror

$ npm i codemirror

Note: I did initially try and just use the codemirror.js file from the downloadable zip (to try and keep everything a little smaller and concise) but I ran into a few issues so reverted to using the npm package

and then we can import it into our react file

import CodeMirror from "codemirror";

Now we can create our textarea which will become our code editor

import React from "react"
import CodeMirror from "codemirror"
function Editor(props) {
return (
<div>
<textarea
defaultValue={`<style>
.body{
background: blue
}
</style>`}
/>
</div>
)
}
export default Editor

Then we need to use useRef and the ref attribute to access the textarea DOM element. This is needed so we can tell Codemirror what element to turn into a code editor later on.

import React, { useRef } from "react"
import CodeMirror from "codemirror"
function Editor(props) {
const editor = useRef(null)
return (
<div>
<textarea
ref={editor}
defaultValue={`<style>
.body{
background: blue
}
</style>`}
/>
</div>
)
}
export default Editor

Next we need to initialise CodeMirror, and to do that we need to use the useEffect React Hook (you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.)

So when our component has mounted and the DOM we can create a CodeMirror editor instance

import React, { useEffect, useRef } from "react"
import CodeMirror from "codemirror"
function Editor(props) {
const editor = useRef(null)
useEffect(() => {
CodeMirror.fromTextArea(editor.current, {
lineNumbers: false,
mode: "htmlmixed",
theme: "one-dark",
tabSize: 1,
})
})
return (
<div>
<textarea
ref={editor}
defaultValue={`<style>
.body{
background: blue
}
</style>`}
/>
</div>
)
}
export default Editor

And this is the basic setup done! Now I have added some other features which I will stick below and talk through a little

import React, { useEffect, useRef } from "react"
import styled from "styled-components"
import CodeMirror from "codemirror"
import "../lib/CodeMirror/codemirror.css"
import "../lib/CodeMirror/one-dark.css"
import "codemirror/mode/javascript/javascript"
import "codemirror/mode/xml/xml"
import "codemirror/mode/css/css"
import "codemirror/mode/htmlmixed/htmlmixed"
import "codemirror/addon/edit/closebrackets"
import "codemirror/addon/edit/closetag"
import "codemirror/addon/search/searchcursor"
import "codemirror/keymap/sublime"
const CodeEditor = styled.div`
.CodeMirror {
line-height: 1.4;
}
.cm-s-one-dark.CodeMirror,
textarea {
padding: 35px 25px 25px 25px;
border-radius: 3px;
background: #21252b;
}
`
function Editor(props) {
const editor = useRef(null)
useEffect(() => {
CodeMirror.fromTextArea(editor.current, {
lineNumbers: false,
mode: "htmlmixed",
theme: "one-dark",
autoCloseBrackets: true,
autoCloseTags: true,
tabSize: 1,
keyMap: "sublime",
})
})
return (
<CodeEditor>
<textarea
ref={editor}
defaultValue={`<style>
.body{
background: blue
}
</style>`}
/>
</CodeEditor>
)
}
export default Editor

So to explain a little, I am using the one dark theme by Török Ádám which can be found here, created a file within src and imported it. Then I have added the theme name to the Codemirror instance options and so it knows what styles to use.

The code that will be written in the editor will be a mix of css, html and javascript therefore I am using htmlmixed mode. There are a bunch of other options you can use such as just javascript, css and xml (for HTML) just take a look at the CodeMirror docs to find the one relevant for your project.

Because I'm using htmlmixed I need to import the javascript, xml, css and htmlmixed js files from codemirrors mode directory for it to work correctly (the imports will differ depending on the mode you're using). This was the biggest pain point for me and it took me a bit of time to figure it out.

And lastly I'm importing and declaring some addons which will add some useful features to the editor. See autoCloseBrackets: true, autoCloseTags: true and keyMap: "sublime" options have been added to the CodeMirror instance as well as importing the files.

One important thing to notice is that the one-dark.css was the only extra file needed, all of the addons and syntax highlighting was imported directly from the codemirror dependency. By not adding a ./ or ../ before the import your js files are presumed to live in your node_modules.

Hope you have enjoyed this post and have a go setting up your own CodeMirror instance in React!

Please let me know if you found anything I wrote confusing, incorrect or outdated. Write a few words below and I will use your suggestions to improve this post.