How to use "append" create a structure for a side-menu in the editor and also is it possible to disable a plugin on selection of another one.
If you need to customize a component read and understand how they work here: https://grapesjs.com/docs/modules/Components.html You have total control over the component in the canvas by using its View
Read full answer below ↓Question
[Question]: 1.) I am trying to create a hamburger sidebar for the full-screen view instead of just the mobile view. But when we have dropped the plugin, on dropping any other plugin it is not getting a proper structure on the body to separate the other content and is overlapping. Is there any way to avoid it.
2.) Also on dropping of hamburger side menu, I want the Menu plugin should be disabled. Is there a way to do so.
3.) I would be very helpful if you help it implement it any other way if possible.
For reference: - I have used the menu default plugin and changed a bit to serve my purpose. I am attaching relevant files with respect to the plugin.
**_Index.js_**
`import grapesjs from 'grapesjs';
import loadBlocks from './blocks';
import loadComponents from './components';
import {
hNavbarRef, navbarRef, navbarItemsRef, menuRef
} from './consts';
export default grapesjs.plugins.add('ef-hamburger', (editor, opts = {}) => {
let c = opts;
let defaults = {
blocks: [hNavbarRef],
defaultStyle: 1,
navbarClsPfx: 'navbar',
labelNavbar: 'navbar',
labelNavbarContainer: 'Navbar Container',
labelMenu: 'Navbar Menu',
labelMenuLink: 'Menu link',
labelBurger: 'Burger',
labelBurgerLine: 'Burger Line',
labelNavbarBlock: 'Hamburger',
labelNavbarCategory: 'Extra',
labelHome: 'Home',
labelAbout: 'About',
labelContact: 'Contact',
};
// Load defaults
for (let name in defaults) {
if (!(name in c))
c[name] = defaults[name];
}
loadBlocks(editor, c);
loadComponents(editor, c);
});
`
**_consts.js_**
`export const
hNavbarRef = 'h-navbar',
navbarRef = 'navbar',
navbarItemsRef = 'navbar-items',
menuRef = 'navbar-menu';
`
**_component.js_**
`export default (editor, opt = {}) => {
const c = opt;
const dc = editor.DomComponents;
const defaultType = dc.getType('default');
const defaultModel = defaultType.model;
const burgerType = 'burger-menu';
dc.addType(burgerType, {
model: defaultModel.extend({
defaults: {
...defaultModel.prototype.defaults,
'custom-name': c.labelBurger,
draggable: false,
droppable: false,
copyable: false,
removable: false,
script: function () {
var transEndAdded;
var isAnimating = 0;
var stringCollapse = 'gjs-collapse';
var clickEvent = 'click';
var transitProp = 'max-height';
var transitTiming = 'ease-in-out';
var transitSpeed = 0.25;
var getTransitionEvent = function() {
var t, el = document.createElement('void');
var transitions = {
'transition': 'transitionend',
'OTransition': 'oTransitionEnd',
'MozTransition': 'transitionend',
'WebkitTransition': 'webkitTransitionEnd'
}
for (t in transitions) {
if (el.style[t] !== undefined){
return transitions[t];
}
}
}
var transitEndEvent = getTransitionEvent();
var getElHeight = function(el) {
var style = window.getComputedStyle(el);
var elDisplay = style.display;
var elPos = style.position;
var elVis = style.visibility;
var currentHeight = style.height;
var elMaxHeight = parseInt(style[transitProp]);
if (elDisplay !== 'none' && elMaxHeight !== '0') {
return el.offsetHeight;
}
el.style.height = 'auto';
el.style.display = 'block';
el.style.position = 'absolute';
el.style.visibility = 'hidden';
var height = el.offsetHeight;
el.style.height = '';
el.style.display = '';
el.style.position = '';
el.style.visibility = '';
return height;
};
var toggleSlide = function(el) {
isAnimating = 1;
var elMaxHeight = getElHeight(el);
var elStyle = el.style;
elStyle.display = 'block';
elStyle.transition = transitProp + ' ' + transitSpeed + 's ' + transitTiming;
elStyle.overflowY = 'hidden';
if (elStyle[transitProp] == '') {
elStyle[transitProp] = 0;
}
if (parseInt(elStyle[transitProp]) == 0) {
elStyle[transitProp] = '0';
setTimeout(function() {
elStyle[transitProp] = elMaxHeight + 'px';
}, 10);
} else {
elStyle[transitProp] = '0';
}
}
var toggle = function(e) {
e.preventDefault();
if (isAnimating) {
return;
}
var navParent = this.closest(`[data-gjs=navbar]`);
var navItems = navParent.querySelector(`[data-gjs=navbar-items]`);
toggleSlide(navItems);
if (!transEndAdded) {
navItems.addEventListener(transitEndEvent, function() {
isAnimating = 0;
var itemsStyle = navItems.style;
if (parseInt(itemsStyle[transitProp]) == 0) {
itemsStyle.displatoggleSlidey = '';
itemsStyle[transitProp] = '';
}
});
transEndAdded = 1;
}
};
if ( !(stringCollapse in this ) ) {
this.addEventListener(clickEvent, toggle);
}
this[stringCollapse] = 1;
},
},
}, {
isComponent(el) {
if(el.getAttribute &&
el.getAttribute('data-gjs-type') == burgerType) {
return {type: burgerType};
}
},
}),
view: defaultType.view,
});
}
`
**_blocks.js_**
`import {
hNavbarRef,
navbarRef,
navbarItemsRef,
menuRef
} from "./consts";
export default (editor, opt = {}) => {
const c = opt;
const bm = editor.BlockManager;
const navbarPfx = c.navbarClsPfx || 'navbar';
const style = c.defaultStyle ? `
<style>
body
{
margin: 0;
padding: 0;
// height:auto;
width:auto;
color: black;
font-family: "Avenir Next", "Avenir", sans-serif;
}
a
{
text-decoration: none;
color: #232323;
transition: color 0.3s ease;
}
a:hover
{
color: tomato;
}
#menuToggle
{
display: block;
position: relative;
top: 50px;
left: 50px;
z-index: 1;
background-color: #d1c8c8
-webkit-user-select: none;
user-select: none;
}
#menuToggle input
{
display: block;
width: 40px;
height: 32px;
position: absolute;
top: -7px;
left: -5px;
cursor: pointer;
opacity: 0; /* hide this */
z-index: 2; /* and place it over the hamburger */
-webkit-touch-callout: none;
}
/*
* Just a quick hamburger
*/
#menuToggle span
{
display: block;
width: 33px;
height: 4px;
margin-bottom: 5px;
position: relative;
background: #cdcdcd;
border-radius: 3px;
z-index: 1;
transform-origin: 4px 0px;
transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0),
background 0.5s cubic-bezier(0.77,0.2,0.05,1.0),
opacity 0.55s ease;
}
#menuToggle span:first-child
{
transform-origin: 0% 0%;
}
#menuToggle span:nth-last-child(2)
{
transform-origin: 0% 100%;
}
/*
* Transform all the slices of hamburger
* into a crossmark.
*/
#menuToggle input:checked ~ span
{
opacity: 1;
transform: rotate(45deg) translate(-2px, -1px);
background: #232323;
}
/*
* But let's hide the middle one.
*/
#menuToggle input:checked ~ span:nth-last-child(3)
{
opacity: 0;
transform: rotate(0deg) scale(0.2, 0.2);
}
/*
* Ohyeah and the last one should go the other direction
*/
#menuToggle input:checked ~ span:nth-last-child(2)
{
transform: rotate(-45deg) translate(0, -1px);
}
/*
* Make this absolute positioned
* at the top left of the screen
*/
#menu
{
position: absolute;
width: 150px;
margin: -100px 500px 100px -50px;
padding: 50px;
padding-top: 125px;
height:105vh;
background-color: #d1c8c8;
list-style-type: none;
-webkit-font-smoothing: antialiased;
/* to stop flickering of text in safari */
transform-origin: 0% 0%;
transform: translate(-100%, 0);
transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0);
}
#menu li
{
padding: 10px 0;
font-size: 22px;
}
/*
* And let's slide it in from the left
*/
#menuToggle input:checked ~ ul
{
transform: none;
}
.hamburgercontainer {
width:2em
height:100vh;
}
.full-height {
height: 100vh;
}
</style>
` : '';
bm.add(hNavbarRef, {
label: `
<svg class="gjs-block-svg" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
// <path class="gjs-block-svg-path" d="M22,9 C22,8.4 21.5,8 20.75,8 L3.25,8 C2.5,8 2,8.4 2,9 L2,15 C2,15.6 2.5,16 3.25,16 L20.75,16 C21.5,16 22,15.6 22,15 L22,9 Z M21,15 L3,15 L3,9 L21,9 L21,15 Z" fill-rule="nonzero"></path>
<rect class="gjs-block-svg-path" x="15" y="10" width="5" height="1"></rect>
<rect class="gjs-block-svg-path" x="15" y="10" width="5" height="1"></rect>
<rect class="gjs-block-svg-path" x="15" y="10" width="5" height="1"></rect>
</svg>
<div class="gjs-block-label">${c.labelNavbarBlock}</div>`,
category: 'Event Gadgets',
content: `
<div class = "hamburgercontainer">
<!-- Made by Erik Terwan -->
<!-- 24th of November 2015 -->
<!-- MIT License -->
<div id="menuToggle">
<!--
A fake / hidden checkbox is used as click reciever,
so you can use the :checked selector on it.
-->
<input type="checkbox" />
<!--
Some spans to act as a hamburger.
They are acting like a real hamburger,
not that McDonalds stuff.
-->
<span></span>
<span></span>
<span></span>
<!--
Too bad the menu has to be inside of the button but hey, it's pure CSS magic.
-->
<ul id="menu">
<a href="#"><li>Home</li></a>
<a href="#"><li>About</li></a>
<a href="#"><li>Info</li></a>
<a href="#"><li>Contact</li></a>
</ul>
</div>
</div>
${style}
`,
components:[{
tagName: 'div',
removable: true,
draggable: false,
copyable: true,
droppable:false
}],
});
}
`

Answers (1)
If you need to customize a component read and understand how they work here: https://grapesjs.com/docs/modules/Components.html You have total control over the component in the canvas by using its View
Related Questions and Answers
Continue research with similar issue discussions.
Issue #1504
[Question] Dynamic height
Hi: Is it possible to have an instance of GrapesJS with dynamic height, as in, the editor adjusts to the content size. What I'm trying to d...
Issue #3258
Prevent/Disable Custom Blocks from being dropped inside other Custom Blocks
Hello, I have a custom component, let's call it a Section Block. I want to prevent the user from dropping Section Blocks inside other Secti...
Issue #853
[QUESTION] Create Body's trait fixed
I'm trying to create two inputs (width and backgound-color) to template's body and I would like to fix it in Panel's view. When a component...
Issue #2687
[Question] How to append style manager to custom panel
I would like to append the whole style manager module to a panel? I have been digging up the docs for the past 2 days and couldn't find a p...
Paid Plugins That Match This Issue
Curated by issue keywords and label relevance to help you ship faster.
Loading paid plugin recommendations...
Check the open-source GrapesJS plugins on GitHub or run a quick search in our free catalog.
Browse free plugins →Premium plugins ship with support, regular updates, and production-ready features — save days of integration work.
Browse premium plugins →Related tutorials
In-depth guides on the same topic.
Tutorial
How to Build a Production GrapesJS Editor: The Complete Walkthrough of Brief, Preset, Plugins, and Services
A complete walkthrough of building a production GrapesJS editor: how to choose a preset, pick plugins, and scope setup services without burning a sprint.
Tutorial
Embed GrapesJS in Your SaaS: A Weekend Guide
Embed GrapesJS in your SaaS and ship a white-label page builder over a weekend. Honest tradeoffs, real code, and the plugins that close the UX gap.
Tutorial
Big Updates: TinyMCE 8 and Placeholder 2.0 for GrapesJS
In May we shipped major updates to two of our most popular GrapesJS plugins — TinyMCE Inline Text Editor and Placeholder.
Browse Plugin Categories
Jump directly to plugin category pages on the marketplace.