= (editor, options) => {
// ...
};
grapesjs.init({
// ...
plugins: [\
// no need for `pluginsOpts`\
usePlugin(myPlugin, { opt1: 'A', opt2: 1 }),\
],
});
[#](#boilerplate)
Boilerplate
------------------------------
For fast plugin development, we highly recommend using [grapesjs-cli (opens new window)](https://github.com/GrapesJS/cli)
which helps to avoid the hassle of setting up all the dependencies and configurations for development and building (no need to touch Webpack or Babel configurations). For more information check the repository.
← [Modal](/docs/modules/Modal.html) [Symbols](/docs/guides/Symbols.html)
→
---
# GrapesJS
[#](#parser)
Parser
--------------------
You can customize the initial state of the module from the editor initialization, by passing the following [Configuration Object (opens new window)](https://github.com/GrapesJS/grapesjs/blob/master/src/parser/config/config.ts)
const editor = grapesjs.init({
parser: {
// options
}
})
Once the editor is instantiated you can use its API. Before using these methods you should get the module from the instance
const { Parser } = editor;
[#](#available-events)
Available Events
----------------------------------------
* `parse:html` - On HTML parse, an object containing the input and the output of the parser is passed as an argument
* `parse:css` - On CSS parse, an object containing the input and the output of the parser is passed as an argument
[#](#methods)
Methods
----------------------
* [getConfig](#getconfig)
* [parseHtml](#parsehtml)
* [parseCss](#parsecss)
[#](#getconfig)
getConfig
--------------------------
Get configuration object
Returns **[Object (opens new window)](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)
**
[#](#parsehtml)
parseHtml
--------------------------
Parse HTML string and return the object containing the Component Definition
### [#](#parameters)
Parameters
* `input` **[String (opens new window)](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)
** HTML string to parse
* `options` **[Object (opens new window)](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)
?** Options (optional, default `{}`)
* `options.htmlType` **[String (opens new window)](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)
?** [HTML mime type (opens new window)](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#Argument02)
to parse
* `options.allowScripts` **[Boolean (opens new window)](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)
** Allow `
In the example above we're relying on two hidden inputs, one for containing the project data and the another one for the HTML/CSS.
[#](#events)
Events
--------------------
For a complete list of available events, you can check it [here](/docs/api/storage_manager.html#available-events)
.
← [Style Manager](/docs/modules/Style-manager.html) [Modal](/docs/modules/Modal.html)
→
---
# Symbols | GrapesJS
[#](#symbols)
Symbols
======================
WARNING
This feature is released as a beta from GrapesJS v0.21.11
To get a better understanding of the content in this guide we recommend reading [Components](/docs/modules/Components.html)
first
Symbols are a special type of [Component](/docs/modules/Components.html)
that allows you to easily reuse common elements across your project. They are particularly useful for components that appear multiple times in your project and need to remain consistent. By using Symbols, you can easily update these components in one place and have the changes reflected everywhere they are used.
* [Concept](#concept)
* [Programmatic usage](#programmatic-usage)
* [Create symbol](#create-symbol)
* [Symbol details](#symbol-details)
* [Overrides](#overrides)
* [Detach symbol](#detach-symbol)
* [Remove symbol](#remove-symbol)
* [Events](#events)
* [Example](#example)
[#](#concept)
Concept
----------------------
A Symbol created from a component retains the same shape and uses the same [Components API](/docs/api/component.html)
, but it includes a reference to other related Symbols. When you create a new Symbol from a Component, it creates a Main Symbol, and the original component becomes an Instance Symbol.
When you reuse the Symbol elsewhere, it creates new Instance Symbols. Any updates made to the Main Symbol are automatically replicated in all Instance Symbols, ensuring consistency throughout your project.
Below is a simple representation of the connection between Main and Instance Symbols.

Note
This feature operates at a low level, meaning there is no built-in UI for creating and managing symbols. Developers need to implement their own UI to interact with this feature. Below you'll find an example of implementation.
[#](#programmatic-usage)
Programmatic usage
--------------------------------------------
Let's see how to work with and manage Symbols in your project.
### [#](#create-symbol)
Create symbol
Create a new Symbol from any component in your project:
const anyComponent = editor.getSelected();
const symbolMain = editor.Components.addSymbol(anyComponent);
This will transform `anyComponent` to an Instance and the returned `symbolMain` will be the Main Symbol. GrapesJS keeps track of Main Symbols separately in your project JSON, and they will be automatically reconnected when you reload the project.
The `addSymbol` method also handles the creation of Instances. If you call it again by passing `symbolMain` or `anyComponent`, it will create a new Instance of `symbolMain`.
const secondInstance = editor.Components.addSymbol(symbolMain);
Now, `symbolMain` references two instances of its shape.
To get all the available Symbols in your project, use `getSymbols`:
const symbols = editor.Components.getSymbols();
const symbolMain = symbols[0];
### [#](#symbol-details)
Symbol details
Once you have Symbols in your project, you might need to know when a Component is a Symbol and get details about it. Use the `getSymbolInfo` method for this:
// Details from the Main Symbol
const symbolMainInfo = editor.Components.getSymbolInfo(symbolMain);
symbolMainInfo.isSymbol; // true; It's a Symbol
symbolMainInfo.isRoot; // true; It's the root of the Symbol
symbolMainInfo.isMain; // true; It's the Main Symbol
symbolMainInfo.isInstance; // false; It's not the Instance Symbol
symbolMainInfo.main; // symbolMainInfo; Reference to the Main Symbol
symbolMainInfo.instances; // [anyComponent, secondInstance]; Reference to Instance Symbols
symbolMainInfo.relatives; // [anyComponent, secondInstance]; Relative Symbols
// Details from the Instance Symbol
const secondInstanceInfo = editor.Components.getSymbolInfo(secondInstance);
symbolMainInfo.isSymbol; // true; It's a Symbol
symbolMainInfo.isRoot; // true; It's the root of the Symbol
symbolMainInfo.isMain; // false; It's not the Main Symbol
symbolMainInfo.isInstance; // true; It's the Instance Symbol
symbolMainInfo.main; // symbolMainInfo; Reference to the Main Symbol
symbolMainInfo.instances; // [anyComponent, secondInstance]; Reference to Instance Symbols
symbolMainInfo.relatives; // [anyComponent, symbolMain]; Relative Symbols
### [#](#overrides)
Overrides
When you update a Symbol's properties, changes are propagated to all related Symbols. To avoid propagating specific properties, you can specify at the component level which properties to skip:
anyComponent.set('my-property', true);
secondInstance.get('my-property'); // true; change propagated
anyComponent.setSymbolOverride(['my-property']);
// Get current override value: anyComponent.getSymbolOverride();
anyComponent.set('my-property', false);
secondInstance.get('my-property'); // true; change didn't propagate
### [#](#detach-symbol)
Detach symbol
Once you have Symbol instances you might need to disconnect one to create a new custom shape with other components inside, in that case you can use `detachSymbol`.
editor.Components.detachSymbol(anyComponent);
const info = editor.Components.getSymbolInfo(anyComponent);
info.isSymbol; // false; Not a Symbol anymore
const infoMain = editor.Components.getSymbolInfo(symbolMain);
infoMain.instances; // [secondInstance]; Removed the reference
### [#](#remove-symbol)
Remove symbol
To remove a Main Symbol and detach all related instances:
const symbolMain = editor.Components.getSymbols()[0];
symbolMain.remove();
[#](#events)
Events
--------------------
The editor triggers several symbol-related events that you can leverage for your integration:
* `symbol:main:add` Added new root main symbol.
editor.on('symbol:main:add', ({ component }) => { ... });
* `symbol:main:update` Root main symbol updated.
editor.on('symbol:main:update', ({ component }) => { ... });
* `symbol:main:remove` Root main symbol removed.
editor.on('symbol:main:remove', ({ component }) => { ... });
* `symbol:main` Catch-all event related to root main symbol updates.
editor.on('symbol:main', ({ event, component }) => { ... });
* `symbol:instance:add` Added new root instance symbol.
editor.on('symbol:instance:add', ({ component }) => { ... });
* `symbol:instance:remove` Root instance symbol removed.
editor.on('symbol:instance:remove', ({ component }) => { ... });
* `symbol:instance` Catch-all event related to root instance symbol updates.
editor.on('symbol:instance', ({ event, component }) => { ... });
* `symbol` Catch-all event for any symbol update (main or instance).
editor.on('symbol', () => { ... });
[#](#example)
Example
----------------------
Below is a basic UI implementation leveraging the Symbols API:
← [Plugins](/docs/modules/Plugins.html) [Replace Rich Text Editor](/docs/guides/Replace-Rich-Text-Editor.html)
→
---
# Use Custom CSS Parser | GrapesJS
[#](#use-custom-css-parser)
Use Custom CSS Parser
==================================================
If you just use GrapesJS for building templates from scratch, so you start from an empty canvas and for editing you strictly rely on the generated JSON (final HTML/CSS only for end-users) then, probably, you might skip this guide. On the other hand, if you import templates from already defined HTML/CSS or let the user embed custom codes (eg. using the [grapesjs-custom-code (opens new window)](https://github.com/GrapesJS/components-custom-code)
plugin), then you have to know that you might face strange behaviors.
WARNING
This guide requires GrapesJS v0.14.33 or higher
* [Import HTML/CSS](#import-html-css)
* [CSSOM results are inconsistent](#cssom-results-are-inconsistent)
* [Results](#results)
* [CSSOM results can be nonintuitive](#cssom-results-can-be-nonintuitive)
* [Set CSS parser](#set-css-parser)
* [Rule Objects](#rule-objects)
* [Plugins](#plugins)
[#](#import-html-css)
Import HTML/CSS
--------------------------------------
Importing already defined HTML/CSS is a really good feature as it lets you start editing immediately any kind of template and obviously, GrapesJS itself promotes this kind of approach
To work fast and easier GrapesJS needs to compile a simple string (HTML/CSS) into structured nodes (nested JS objects). Fortunately, most of the hard work (parsing) is already done by the browser itself which translates that string into its own objects ([DOM (opens new window)](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model)
/[CSSOM (opens new window)](https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model)
) and so we just rely on those, by traversing them and creating our nodes (unfortunately browser's objects are not enough). The fact we're able to parse our strings just by using the browser itself it's very cool, we can enable the import feature without requiring any third-party library, so... where is the problem? Well, while the generated DOM is performing quite well, as we're able to extract what we need, unfortunately, it's not the same for the CSSOM, so let's see in the next paragraph what is wrong with it.
[#](#cssom-results-are-inconsistent)
CSSOM results are inconsistent
--------------------------------------------------------------------
Unfortunately, we have discovered that the CSSOM generated by browsers are highly inconsistent from what we ask to parse. To demonstrate it, we gonna create a simple example by using the built-in parser and we'll check its result. So, for our case we just take in account a simple rule, we'll parse it and print the CSSOM result on screen.
To parse
.simple-class {
background-image:url("https://image1.png"), url("https://image2.jpg");
background-attachment: fixed, scroll;
background-position:left top, center center;
background-repeat:repeat-y, no-repeat;
background-size: contain, cover;
box-shadow: 0 0 5px #9d7aa5, 0 0 10px #e6c3ee;
border: 2px solid #FF0000;
}
Result
### [#](#results)
Results
Here some results (using latest versions + IE11)

As you see, this is what we get for asking only 7 properties, who adds more or less, someone converts colors to rgba functions and someone else changes the order of our values (eg. `box-shadow`). Webkit-based browsers attach also properties they self don't understand

So it's clear that we can't rely on CSSOM objects, that's why we added the possibility to set custom CSS parser via `editor.setCustomParserCss` method or `config.Parser.parserCss` option to use on initialization. Let's see in detail how it's expected to work
[#](#cssom-results-can-be-nonintuitive)
CSSOM results can be nonintuitive
--------------------------------------------------------------------------
As per current [csswg specification (opens new window)](https://drafts.csswg.org/css-variables-1/#variables-in-shorthands)
variables in shorthand properties can serialize to the empty string. This means that while `background-color: var(--my-var)` will serialize fine `background: var(--my-var)` will not.
[#](#set-css-parser)
Set CSS parser
------------------------------------
The custom parser you have to use it's just a function receiving 2 arguments: `css`, as the CSS string to parse, and `editor`, the instance of the current editor. As the result, you should return an array containing valid rule objects, the syntax of those objects are explained below. This is how you can set the custom parser
const parserCss = (css, editor) => {
const result = [];
// ... parse the CSS string
result.push({
selectors: '.someclass, div .otherclass',
style: { color: 'red' },
});
// ...
return result; // Result should be ALWAYS an array
};
// On initialization
// This is the recommended way, as you gonna use the parser from the beginning
const editor = grapesjs.init({
//...
parser: {
parserCss,
},
});
// Or later, via editor API
editor.setCustomParserCss(parserCss);
[#](#rule-objects)
Rule Objects
--------------------------------
The syntax of rule objects is pretty straightforward, each object might contain following keys
| Key | Description | Example |
| --- | --- | --- |
| `selectors` | Selectors of the rule.
**REQUIRED** return an empty string in case the rule has no selectors | `.class1, div > #someid` |
| `style` | Style declarations as an object | `{ color: 'red' }` |
| `atRule` | At-rule name | `media` |
| `params` | Parameters of the at-rule | `screen and (min-width: 480px)` |
To make it more clear let's see a few examples
// Input
`
@font-face {
font-family: "Font Name";
src: url("https://font-url.eot");
}
`
// Output
[\
{\
selectors: '',\
atRule: 'font-face',\
style: {\
'font-family': '"Font Name"',\
src: 'url("https://font-url.eot")',\
},\
}\
]
// Input
`
@keyframes keyframe-name {
from { opacity: 0; }
to { opacity: 1; }
}
`
// Output
[\
{\
params: 'keyframe-name',\
selectors: 'from',\
atRule: 'keyframes',\
style: {\
opacity: '0',\
},\
}, {\
params: 'keyframe-name',\
selectors: 'to',\
atRule: 'keyframes',\
style: {\
opacity: '1',\
},\
}\
]
// Input
`
@media screen and (min-width: 480px) {
body {
background-color: lightgreen;
}
.class-test, .class-test2:hover {
color: blue !important;
}
}
`
// Output
[\
{\
params: 'screen and (min-width: 480px)',\
selectors: 'body',\
atRule: 'media',\
style: {\
'background-color': 'lightgreen',\
},\
}, {\
params: 'screen and (min-width: 480px)',\
selectors: '.class-test, .class-test2:hover',\
atRule: 'media',\
style: {\
color: 'blue !important',\
},\
}\
]
// Input
`
:root {
--some-color: red;
--some-width: 55px;
}
`
// Output
[\
{\
selectors: ':root',\
style: {\
'--some-color': 'red',\
'--some-width': '55px',\
},\
},\
]
[#](#plugins)
Plugins
----------------------
Below the list of current available CSS parsers as plugins, if you need to create your own we highly suggest to explore their sources
* [grapesjs-parser-postcss (opens new window)](https://github.com/GrapesJS/parser-postcss)
- Using [PostCSS (opens new window)](https://github.com/postcss/postcss)
parser
← [Replace Rich Text Editor](/docs/guides/Replace-Rich-Text-Editor.html) [GrapesJS Telemetry](/docs/guides/Telemetry.html)
→
---
# GrapesJS Telemetry | GrapesJS
[#](#grapesjs-telemetry)
GrapesJS Telemetry
============================================
We collect and use data to improve GrapesJS. This page explains what data we collect and how we use it.
[#](#what-data-we-collect)
What data we collect
------------------------------------------------
We collect the following data:
* **domain**: The domain of the website where GrapesJS is used.
* **version**: The version of GrapesJS used.
* **timestamp**: The time when the editor is loaded.
[#](#how-we-use-data)
How we use data
--------------------------------------
We use data to:
* **Improve GrapesJS**: We use data to improve GrapesJS. For example, we use data to identify bugs and fix them.
* **Analyze usage**: We use data to analyze how GrapesJS is used. For example, we use data to understand which features are used most often.
* **Provide support**: We use data to provide support to users. For example, we use data to understand how users interact with GrapesJS.
[#](#how-to-opt-out)
How to opt-out
------------------------------------
You can opt-out of data collection by setting the `telemetry` option to `false` when initializing GrapesJS:
const editor = grapesjs.init({
// ...
telemetry: false,
});
← [Use Custom CSS Parser](/docs/guides/Custom-CSS-parser.html)
---
# 404: This page could not be found.
404
===
This page could not be found.
-----------------------------
---
# 404: This page could not be found.
404
===
This page could not be found.
-----------------------------
---