DEV Community

Alonzo
Alonzo

Posted on

Fixing "navigator is not defined" when using Codemirror with NextJS

If you have tried to implement CodeMirror in a NextJS project, you may have seen an error like this everytime you refresh the page:

Navigator not defined error

Instead of hoping that your user would not refresh the page or removing CodeMirror all together, you could try to fix it. Here's how.

Before starting ensure that you do have react-codemirror and codemirror installed. If not, copy and paste the following within your terminal


// if you have npm

npm i codemirror

npm i react-codemirror

//if you have yarn

yarn add codemirror

yarn add react-codemirror

Enter fullscreen mode Exit fullscreen mode

Dynamic Importing

First, you need to make sure that you import react-codemirror and your desired themes and modes using Dynamic imports. To do this, import the dynamic function from NextJS normally as you would with any other npm/yarn package.


import dynamic from 'next/dynamic'

Enter fullscreen mode Exit fullscreen mode

With this function imported, you can start to dynamically import react-codemirror and it's dependencies. Keep in mind though that you have to dynamically import these outside your exported function. Create a const called CodeMirror and set it equal to the dynamic function. Inside the dynamic function, import the dependencies (e.g. import('codemirror/mode/xml/xml')) and then return with import('react-codemirror'). After you have imported all of these, add an object within the function declaring ssr: false. In the end, it should look something like this:


const CodeMirror = dynamic(() => {
    import('codemirror/mode/xml/xml')
    import('codemirror/mode/javascript/javascript')
    import('codemirror/mode/css/css')
    import('codemirror/mode/markdown/markdown')
    import('codemirror/theme/material-ocean.css')
    return import('react-codemirror')
}, {ssr: false})

Enter fullscreen mode Exit fullscreen mode

Rendering

To include the CodeMirror element within your page/component, you first need to enclose it within brackets. After that, you can include everything else such as the value, options, and the onChange event. E.G.:


{<CodeMirror
    className="editor"
    value={devLog}
    name= "Devlog"
    options={{
      theme: 'mdn-like',
      lineNumbers: true,
      mode: 'markdown'
    }}
    onChange={devLog => setDevLog(devLog)}
/>}

Enter fullscreen mode Exit fullscreen mode

To ensure that it everything looks right and works the way you expect it to work (not having the textarea and editor being in two separate places or a bunch of x's), you should include the following in your _app.js file


import 'codemirror/lib/codemirror.css'

Enter fullscreen mode Exit fullscreen mode

In the end, you and your users should be able to write code or write a markdown blog using CodeMirror without having to worry about refreshing the page only to see an error.

Latest comments (1)

Collapse
 
philippe profile image
Philippe Bernard

Thank you very much for this solution! I think there is something missing: the imports return promises and the function passed to dynamic should make sure the final promise importing react-codemirror doesn't resolve before the other promises do. When I used you code as is, I could sometimes observe inconsistencies (theme not applied, addon not available). The simplest solution is to make the function async, and await each imports.