Monaco editor dynamically resizable

19,481

Solution 1

TL;DR: add automaticLayout: true to your editor's configuration.

NL;PR:

Monaco has a built-in auto resize to parent container functionality:

React >= 16.3.0

    componentDidMount(){
     let editor = monaco.editor.create(this.editorDiv.current, {
            value: "var x = 0;",
            language: 'javascript',
            automaticLayout: true // <<== the important part
          });
    }
    constructor(props){super(props); this.editorDiv = React.createRef();}
    render(){return <div ref={this.editorDiv} className="editor" ></div>}

React<16.3.0

    render(){
     return <div ref={el=>{this.editorDiv = el}} className="editor" ></div>
    }
     // I use this configuration in the editor:
    componentDidMount(){
     let editor = monaco.editor.create(this.editorDiv, {
            value: "var x = 0;",
            language: 'javascript',
            automaticLayout: true // <<== the important part
          });
    }

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.30.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

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

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

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

Share:
19,481

Related videos on Youtube

elenaHristova
Author by

elenaHristova

Updated on June 06, 2022

Comments

  • elenaHristova
    elenaHristova almost 2 years

    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;
    }
    
    • Satnam Sandhu
      Satnam Sandhu over 5 years
      i suggest you to answer your question in the answers section instead of just editing the answer, and accept it. It would be better.
  • atilkan
    atilkan over 5 years
    This is not recommended if you need performance. github.com/Microsoft/monaco-editor/issues/28
  • David I. Samudio
    David I. Samudio almost 5 years
    Did you read the note? polling vs. listening? the official documentation reference?
  • Trevor
    Trevor about 2 years
    Strange. When I set automaticLayout to true and set the editor height to 100%, the editor doesn't grow/resize. As you noted, if I don't set the height, if renders the editor as ~10px the first time, but still doesn't resize.
  • David I. Samudio
    David I. Samudio about 2 years
    What version are you using? I remember there was an issue around version 0.2x. It works correctly when adding the option here: microsoft.github.io/monaco-editor/…