When building the string-strip-html
GUI, I wanted: line wrapping, full-screen flexbox layout, with scrollbars on Codemirror box only. That’s a common layout seen on code-oriented sites like Codepen or Stackblitz. I created a minimal proof-of-concept sandbox to prove it works.
For simplicity, we’ll be using @uiw/react-codemirror
, raw React and pure CSS:
Let me explain the non-trivial parts of this layout.
Outer layout
We have to ensure that every container, including <html>
and <body>
, expands to the 100% of the viewport height with the help of CSS vh
unit:
html,
body,
#root,
.playground-container {
padding: 0;
margin: 0;
height: 100vh; /* <--- */
background-color: #efefef;
}
The CSS vh
unit is supported on all browser versions dated newer than 2013.
Max height via CSS Flexbox
“To let the editor grow until it reaches a maximum height, and scroll from that point on, use
max-height
instead of height in a setup like the one above.”
In CSS Flexbox layout, there’s no max-height
, the container div
, which holds the Codemirror instance, expands with the help of CSS style flex: 1
.
I could only achieve it via flexbox
and setting .cm-scroller
to be absolutely positioned and glue its edges to the parent .cm-editor
container:
.cm-editor {
/* our container wrapper for Codemirror instance */
flex: 1; /* expand to the maximum */
height: 100%;
position: relative; /* needed for child component .cm-scroller */
}
.cm-scroller {
position: absolute !important;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow-y: auto;
}
It took me a couple of hours to discover this setup. The absolute
positioning seems to be the only way to impose scrollbars on Codemirror boxes when its height is unknown and set by CSS Flexbox.
Dark-light themes
If you’re happy with Codemirror default themes, just set the prop theme
on the <CodeMirror/>
component. Below, we’re using remix-themes
so theme
comes from let [theme] = useTheme();
:
import CodeMirror from "@uiw/react-codemirror";
import { html } from "@codemirror/lang-html";
import { EditorView } from "@codemirror/view";
...
<CodeMirror
className="cm-outer-container"
value={inputStr}
extensions={[html(), EditorView.lineWrapping]}
onChange={onChange}
theme={theme || "dark"}
/>
Line wrapping
“To enable line wrapping, add the
EditorView.lineWrapping
extension to your configuration.”—https://codemirror.net/examples/styling/#overflow-and-scrolling
Another challenge is setting up this EditorView.lineWrapping
extension. There are no code examples on the Coremirror docs site showing how to import it and where to place it. For an answer, see the example in the previous section above.
To cause lines to wrap, I chose belt-and-braces: to use EditorView.lineWrapping
(extensions
prop) and to apply CSS directly onto Codemirror elements, as hinted by the documentation (“wrapping can be unreliable if you don’t also set overflow-wrap:
anywhere”). By the way, that’s what CSS Codepen uses:
.cm-content {
white-space: pre-wrap;
word-break: normal;
word-wrap: break-word;
}
Takeaway
Feel free to fork the sandbox and use that layout in your code-processing apps.
Sources
- @uiw
react-codemirror
npm page https://www.npmjs.com/package/@uiw/react-codemirror - @uiw
react-codemirror
GitHub page https://github.com/uiwjs/react-codemirror codemirror
npm page https://www.npmjs.com/package/codemirrorcodemirrror
v6 documentation https://codemirror.net/docs/