'Monaco editor dynamically resizable
I have been searching for a discussion about if it's possible to mimic the html tag textarea's resizing when using Monaco Editor's field all over the Internet but I couldn't find one answering my question.
I'm using the monaco-editor npm package in a React application. Do you have any idea if this is easy to implement?
Thank you in advance!
SOLUTION
With pure css I selected the target html element and just added these properties:
div {
resize: vertical;
overflow: auto;
}
Solution 1:[1]
TL;DR: add automaticLayout: true
to your editor's configuration.
NL;PR:
Monaco has a built-in auto resize to parent container functionality:
createEditorWithAutoResize(){
this.editor = monaco.editor.create(
this.editorDiv.current, {
value: "var x = 0;",
language: 'javascript',
automaticLayout: true // <<== the important part
}
);
}
componentDidMount(){this.createEditorWithAutoResize();}
constructor(props){super(props); this.editorDiv = React.createRef();}
render(){return <div ref={this.editorDiv} className="editor" ></div>}
And the CSS for the editor (it avoids rendering the editor for the first time with like 10px height):
.editor{
height: 100%;
}
First tested: v0.10.1, Last tested: v0.32.1
Note: < v0.20.0: The mechanism does not listen to its container size changes, it polls them.
@nrayburn-tech (Monaco Editor's contributor): Version 0.20 uses MutationObserver for all browsers. Version 0.21 and later uses ResizeObserver on supported browsers, otherwise, it uses polling as a fallback.
Solution 2:[2]
if you have a reference to the editor you can just call
editor.layout()
on some resize event.
For example, on window resize:
window.onresize = function (){
editor.layout();
};
Solution 3:[3]
this is old question but get the problem to and solved it with react-resize-detector
based on ResizeObserver it feet perfectly to the need (check browser compatibility)
Exemple of component :
import React, { Component } from 'react';
import ReactResizeDetector from 'react-resize-detector';
import * as monaco from 'monaco-editor';
class Editor extends Component {
constructor(props) {
super(props)
this.state = {
width: 0,
height: 0,
}
this.editor_div = React.createRef()
this.handle_rezise = this.handle_rezise.bind(this);
}
componentDidMount() {
const editor_model = monaco.editor.createModel('', 'sql');
this.monaco_editor = monaco.editor.create(this.editor_div.current, this.props.editorOptions);
this.monaco_editor.setModel(editor_model);
}
componentWillUnmount() {
this.monaco_editor && this.monaco_editor.dispose();
}
handle_rezise(width, height) {
this.monaco_editor.layout({ height, width });
}
render() {
return(
<div
className="editor-container"
style={{ height: '100%' }}>
<ReactResizeDetector
handleWidth
handleHeight
onResize={ this.handle_rezise }
refreshMode="debounce"
refreshRate={100} />
<div
className="editor"
ref={ this.editor_div }
style={{ height: '100%' }} />
</div>
)
}
}
export default Editor;
Hope it's help
Solution 4:[4]
In my case I'm using that exact CSS but although automaticLayout: true works, I found out overkill (seems to pooling the DOM 100ms interval and I have several editors opened in the document. SO I ended up implementing it manually :
just in case , my needs are different: I want the user to resize it the container - in a standard way and cheap (both on code and performance) on libraries and performance. This is what I did:
css container : resize: vertical; overflow: auto
and this js :
function installResizeWatcher(el, fn, interval){
let offset = {width: el.offsetWidth, height: el.offsetHeight}
setInterval(()=>{
let newOffset = {width: el.offsetWidth, height: el.offsetHeight}
if(offset.height!=newOffset.height||offset.width!=newOffset.width){
offset = newOffset
fn()
}
}, interval)
}
const typeScriptCodeContainer = document.getElementById('typeScriptCodeContainer')
typeScriptCodeEditor = monaco.editor.create(typeScriptCodeContainer, Object.assign(editorOptions, {value: example.codeValue}))
installResizeWatcher(typeScriptCodeContainer, typeScriptCodeEditor.layout.bind(typeScriptCodeEditor), 2000)
yes, 2 seconds interval and make sure it registers only once. I see there is / was a resize interval on 100ms for the automatic relayout in monaco - IMHO that's too much.
See it in action: https://typescript-api-playground.glitch.me/?example=2
Solution 5:[5]
For posterity, the solution I arrived on was to set automaticLayout: false
so that I could perform all the layout in a resize event listener.
const placeholder = document.getElementById('placeholder')
const editor = monaco.editor.create(placeholder, {
value: '// hello world',
language: 'javascript',
automaticLayout: false // or remove, it defaults to false
})
// we need the parent of the editor
const parent = placeholder.parentElement
window.addEventListener('resize', () => {
// make editor as small as possible
editor.layout({ width: 0, height: 0 })
// wait for next frame to ensure last layout finished
window.requestAnimationFrame(() => {
// get the parent dimensions and re-layout the editor
const rect = parent.getBoundingClientRect()
editor.layout({ width: rect.width, height: rect.height })
})
})
By first reducing the editor layout to 0 we can safely query the dimensions of the parent element without the child (editor) contributing to its size. We can then match the editor to the new parent dimensions. Since this takes place over a single frame, there should be no flickering or lag.
Solution 6:[6]
For anyone coming here having this issue in a basic web app (html, css, javascript) I've found a solution for the resizing issue I'm experiencing.
I have the monaco editor in a resizable flex container. It will only grow the width, not shrink it, and vertical resizing doesn't seem to work out of the box.
If you use the monaco config "automaticLayout: true" and the following CSS it seems to resize as expected:
.monaco-editor { position: absolute !important; }
I tried the max-width 99% trick but it causes a laggy delayed effect when increasing the width near edge of page.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Community |
Solution 3 | Naej56 |
Solution 4 | cancerbero |
Solution 5 | Soviut |
Solution 6 | user2808924 |