codemirror, react and height sizing.md

codemirror, react and height sizing.md

If you use codemirror and react together, say through react-codemirror2, then you may have run into sizing issues.

Out of the box, codemirror has a style height setting to 300px on the outer div with classname CodeMirror. react-codemirror2 wraps this with another div called react-codemirror2.

If you don’t load the CSS correctly, the default height of the component is 300px, which is rarely what you want. You generally want the editor to resize based on your overall layout. However, you may have found it difficult to do so. I certrainly did.

The secret is to realize that codemirror add its own scrollbars and manages scrolling in order to optimize content rendering. There are really two modes for setting the height:

  • Set the size of the outer container explicitly with a hight, say 500px using editor.setSize() however this does not refresh when the page changes size.
  • Allow for dynamic resizing but ensure that the the component knows how tall it is.

Generally, you can use one mode or the other. The first approach does not work for me since I need something dynamic. Also, my documents have about 1,000 lines in it, but they don’t have several thousand on average. Hence, I’m ok rendering the entire document at the start. Rendering the entire document at the start is not a requirement for the recipe below. To render the entire document at the start set viewportMargin to Infinity in the options.

I use an flex box for embedding my editors, but the gist of it is that at some point, the proper height on react-codemirror2 is set explicitly:

.component { 
  & :global(.react-codemirror2) {
     height: calc(100% - 32px); /* remove label height above mirror in my case */
  }
}

The trick for responsive styling is to:

  • Set the editor height to auto. This says that the editor should resize to fit its content. Once resized, assuming its smaller than the enclosing container, it then becomes suspectible to overflow settings on the parent container. A large document will overflow its parent container.
  • Set react-codemirror2 to overflow with scrollbars. codemirror2 manages its display area, by default 300px height. It has sub-divs for the horzontal and vertical scrollbars. But when the “component” (through internal code) is set to height: auto it resizes itself to the entire document.

To set the height to auto, you could fiddle with CSS and such to load in the correct order but that’s a bad idea to rely on css load order. You could load the CSS via css loader, but not style loader, then use glamor or something equivalent to take raw css and create a style element, but that’s alot of work as well. Since you are using a component that wraps the actual codemirror2 object, it’s probably easiest to search in the DOM for the outer div or just use react-codemirror2’s editorDidMount callback to set the size: editorDidMount={e => e.setSize(null, "auto")}. You should probably write a component class to remove the lambda from the render loop.

The css for the component is below. It’s specific to how I layout my comonent with a header that is 32px high. I load styles through webpack via style-loader, css-loader and postcss with cssnext) is:

.component {
 & :global(.react-codemirror2) {
        height: calc(100% - 32px);
        overflow: auto; /* you can use hidden here as well */
   }
   ...
}

I personally do not believe that there is any logic here you can follow other than the fact that codemirror2 watches for resizes and uses the parent container setting to adjust the size of its components. For example, if the parent does not allow overflow to happen via auto or hidden, I think codemirror2 adds its own scrollbars. Removing overflow|hidden causes the editor to fill up the entire space beyond its container (which is default behavior when a component overflows). It would be nice to have a mode where it renders the entire document and I can reliably turn off both the sub-divs that represent the horizontal and vertical scrollbars then allow me to control scrolling. Playing with display or visibility did not produce satisfactory results so the recipe above seems to be the best approach.

I also like to make the horizontal scrollbar display all the way to the left, the default seems to leave a notch on the left side for the gutter. I use the following to remove the left notch:

.component {
 & :global(.react-codemirror2) {
        height: calc(100% - 32px);
        overflow: auto;
    & :global(.CodeMirror) {  
        & :global(.CodeMirror-hscrollbar) {
            left: 0px !important;
        }  
    }
 }
 ...
}

Comments

Popular posts from this blog

zio layers and framework integration

typescript and react types

dotty+scala.js+async: interesting options