- GrapesJS Docs Cheatsheet
-
Introduction[2025-03-06] -
Getting Started[2025-03-06] - Modules
-
Components[2025-03-15] -
Components & JS[2025-04-10] - Traits
- Blocks
- Assets
- Commands
- i18n
-
Selectors[2025-04-03] -
Layers[2025-04-08] -
Pages[2025-04-18] - Style Manager
- Storage Manager
- Modal
- Plugins
-
- Guides
- Symbols
- Replace Rich Text Editor
- Use Custom CSS Parser
- GrapesJS Telemetry
GrapesJSis a customizable drag & drop HTML page builder- Can build for example:
- The
canvasis the main part of GrapesJS editor. It's where the template structure is defined.
- A
blockis a reusable piece of HTML that can be dropped on to the canvas.Block Manager APIcan be used to add blocks dynamically
editor.BlockManager.add("my-block-id", {
label: "...",
category: "...",
// ...
});- A block must have a
id,label,contentproperties
- When a
blockis dragged onto thecanvasit becomes aGrapesJS Component - A
componentis anobject- managed in the
View - created by the properties in the
Model - All model properties are reflected in the view
- managed in the
- This section was a bit confusing since it references
Model,Viewand severalManagerswithout much context
PanelscontainButtonsthat can executeactions(built-in or custom) via a buttoncommandproperty
Layersprovide a tree overview of the HTML structure to facilitate moving around elements
StyleManagerallows addingclassname attributes andselector statestocomponentsvia theSelectorManager- This section is a bit confusing, but basically these two managers are used to construct blocks that enable changing the component default styles and customize active:hover:click states
Traitsallow for assigning custom attributes and behaviors to components
- Facilitates responsive site checks via programmatic adjustment of the viewport width
- I had difficulty trying to setup the save feature as described in the Getting Started section. There seems to be missing info regarding the
commandsproperty setup
-
Via CSS variables or CSS class names
-
RECAP: I figured out the styles that work to reproduce the final Get Started setup. However, I haven't figured out how to switch from automatic saving to manually only saves, since that is missing proper documentation. I will need to read through the Storage Manager documentation and possibly delve into the reference API.
- A
componentis the base element of the template.
- Programmatically add components to the canvas:
// Append components directly to the canvas
editor.addComponents(`<div>
<img src="https://path/image" />
<span title="foo">Hello world!!!</span>
</div>`);
// or into some, already defined, component.
// For instance, appending to a selected component would be:
editor.getSelected().append(`<div>...`);
// Actually, editor.addComponents is an alias of...
editor.getWrapper().append(`<div>...`);// surgical programmatic insertion of components
const { length } = component.components();
component.append("<div>...", { at: parseInt(length / 2, 10) });- HTML template strings are parsed into a
Component Definition(an JSON representation of the component) - Truncated example of component JSON definition below ... similar to a
Virtual DOMrepresentation of anDOM element:
{
tagName: 'div',
components: [
{
type: 'image',
attributes: { src: 'https://path/image' },
}, {
tagName: 'span',
type: 'text',
attributes: { title: 'foo' },
components: [{
type: 'textnode',
content: 'Hello world!!!'
}]
}
]
}- Notice that components have an optional
typeproperty (Component Type) that enables the use of built-in/custom components with integrated behaviors - If omitted, the component has
type: 'default' - A component's type is determined via
Component Recognitionwhich is determined by iterating of the HTML template string by creating theComponent Type Stackand use of theisComponentmethod - A
Modelis aComponentinstance
const component = editor.addComponents(`<div>
<img src="https://path/image" />
<span title="foo">Hello world!!!</span>
</div>`)[0];const componentType = component.get("type"); // eg. 'image'// Make the component not draggable
component.set("draggable", false);- Notice that the outer wrapping div is not considered a component ... it sorta represent the containing array in some sense
// `.getAttributes` and `.setAttributes` are also methods on a component instance
const innerComponents = component.components();
innerComponents.forEach((comp) => console.log(comp.toHTML())); // logs the innerHTML of a component
// Update component content
component.components(`<div>Component 1</div><div>Component 2</div>`);The main purpose of the Component is to keep track of its data and to return them when necessary. One common thing you might need to ask from the component is to show its current HTML
- To get back the HTML template string from a component instance:
JSON.stringify(component); - A
Viewis responsible for rendering aComponent
const component = editor.getSelected();
// Get the View
const view = component.getView();
// Get the DOM element
const el = component.getEl();The Model/Component is the source of truth for the final code of templates (eg. the HTML export relies on it) and the View/ComponentView is what is used by the editor to preview our components to users in the canvas.
cell(opens new window)- Component for handle and elementsrow(opens new window)- Component for handle elementstable(opens new window)- Component for handle elementsthead(opens new window)- Component for handle elementstbody(opens new window)- Component for handle elementstfoot(opens new window)- Component for handle elementsmap(opens new window)- Component for handle elementslink(opens new window)- Component for handle elementslabel(opens new window)- Component for handle properly elementsvideo(opens new window)- Component for videosimage(opens new window)- Component for imagesscript(opens new window)- Component for handle <script> elementssvg(opens new window)- Component for handle SVG elementscomment(opens new window)- Component for comments (might be useful for email editors)textnode(opens new window)- Similar to the textnode in DOM definition, so a text element without a tag element.text(opens new window)- A simple text component that can be edited inlinewrapper(opens new window)- The canvas need to contain a root component, a wrapper, this component was made to identify itdefault(opens new window)Default base component- Custom Component example:
- Enabling listeners on custom Components Types
- Component Model and View can be extended
- Model and View listeners can also be extended
- Component styles can be added on
model.defaults.stylesproperty - To active Component-First styling behavior
- Next section. Delves into Carousel functionality.
- How to setup JSX syntax parsing. Not relevant for current project.
The first rule of defining new component types is to place the code inside a plugin.
editor.DomComponents.addType("my-input-type", {
// Make the editor understand when to bind `my-input-type`
isComponent: (el) => el.tagName === "INPUT",
// Model definition
model: {
// Default properties
defaults: {
tagName: "input",
draggable: "form, form *", // Can be dropped only inside `form` elements
droppable: false, // Can't drop other elements inside
attributes: {
// Default attributes
type: "text",
name: "default-name",
placeholder: "Insert text here",
},
traits: ["name", "placeholder", { type: "checkbox", name: "required" }],
},
},
});editor.DomComponents.addType("my-input-type", {
// ...
model: {
defaults: {
// ...
someprop: "initial value",
},
init() {
this.on("change:someprop", this.handlePropChange);
// Listen to any attribute change
this.on("change:attributes", this.handleAttrChange);
// Listen to title attribute change
this.on("change:attributes:title", this.handleTitleChange);
},
handlePropChange() {
const { someprop } = this.props();
console.log("New value of someprop: ", someprop);
},
handleAttrChange() {
console.log("Attributes updated: ", this.getAttributes());
},
handleTitleChange() {
console.log("Attribute title updated: ", this.getAttributes().title);
},
},
});comps.addType('my-new-component', {
isComponent: el => {/* ... */},
extend: 'other-defined-component',
model: { ... }, // Will extend the model from 'other-defined-component'
extendView: 'other-defined-component-2',
view: { ... }, // Will extend the view from 'other-defined-component-2'
});domc.addType('new-type', {
extend: 'parent-type',
extendFn: ['init'], // array of model functions to extend from `parent-type`
model: {
init() {
// do something
},
},
extendView: 'other-defined-component-2',
extendFnView: ['init']
view: {
init(){
// do something
}
}
});Each component triggers different lifecycle hooks, which allows you to add custom actions at their specific stages. We can distinguish 2 different types of hooks: global and local. You define local hooks when you create/extend a component type (usually via some model/view method) and the reason is to react to an event of that particular component type. Instead, the global one, will be called indistinctly on any component (you listen to them via editor.on) and you can make use of them for a more generic use case or also listen to them inside other components.
domc.addType("component-css", {
model: {
defaults: {
attributes: { class: "cmp-css" },
components: `
<span>Component with styles<span>
<div class="cmp-css-a">Component A</div>
<div class="cmp-css-b">Component B</div>
`,
styles: `
.cmp-css { color: red }
.cmp-css-a { color: green }
.cmp-css-b { color: blue }
@media (max-width: 992px) {
.cmp-css{ color: darkred; }
.cmp-css-a { color: darkgreen }
.cmp-css-b { color: darkblue }
}
`,
},
},
});grapesjs.init({
...
selectorManager: {
componentFirst: true,
},
})