GrapesJS Starter

HTML

<script src="https://unpkg.com/grapesjs"></script>
<link rel="stylesheet" href="https://unpkg.com/grapesjs/dist/css/grapes.min.css">
<script src="https://unpkg.com/grapesjs-blocks-basic"></script>
<my-editor style="width: 75vw"></my-editor>

CSS

body, html {
  margin: 0;
  height: 100%;
}

Babel + JSX

customElements.define('my-editor', class extends HTMLElement {
        connectedCallback() {
            const root = this.attachShadow({mode: 'open'})
            root.innerHTML = `
      <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/css/grapes.min.css">
      <style>
        :host { display: block; position: relative; height: 600px; }
        #blocks { position: absolute; inset: 0 auto 0 0; width: 160px; overflow: auto; border-right: 1px solid #ccc; }
        #layers { position: absolute; inset: 200px auto 0 0; width: 160px; overflow: auto; border-right: 1px solid #ccc; }
        #gjs { position: absolute; inset: 0 0 0 160px; }
        #gjs .gjs-cv-canvas { width: 100%; height: 100%; top: 0; }
      </style>
      <div id="blocks"></div>
      <div id="layers"></div>
      <div id="gjs"></div>`

            const editor = grapesjs.init({
                container: root.getElementById('gjs'),
                height: '100%',
                storageManager: false,
                panels: {defaults: []},
                blockManager: {
                    appendTo: root.getElementById('blocks'),
                    blocks: [{id: 'section', label: 'Section', content: '<section><h1>Hello</h1></section>'}],
                },
                layerManager: {
                    appendTo: root.getElementById('layers'),
                    sortable: true,
                },
                components: '<div style="padding:40px">Drop a block here</div>',
            })
        }
    })