@ -10,7 +10,7 @@ A [Block] is a simple object which allows the end-user to reuse your [Components
The default UI is a lightweight component with built-in Drag & Drop support, but as you'll see next in this guide, it's easy to extend and create your own UI manager.
::: warning
To get a better understanding of the content in this guide, we recommend reading [Components](Components.html) first
To get a better understanding of the content in this guide, we recommend reading [Components] first
:::
[[toc]]
@ -37,6 +37,10 @@ Check the full list of available options here: [Block Manager Config](https://gi
By default, Block Manager UI is considered a hidden component. Currently, the GrapesJS core, renders default panels and buttons that allow you to show them, but in long term, this is something that might will change. Here below you can see how to init the editor without default panels and immediately rendered Block Manager UI.
::: tip
Follow the [Getting Started] guide in order to setup properly the editor with custom panels.
// The component `image` is activatable (shows the Asset Manager).
// We want to activate it once dropped in the canvas.
activate: true,
// select: true, // Default with `activate: true`
}
],
}
@ -57,6 +71,108 @@ const editor = grapesjs.init({
## Block content types
The key of connecting blocks to components is the `block.content` property and what we passed in the example above is the [Component Definition]. This is the component-oriented way to create blocks and this is how we highly recommend the creation of your blocks.
### Component-oriented
The `content` can accept different formats, like an HTML string (which will be parsed and converted to components), but the component-oriented approach is the most precise as you can keep the control of your each dropped block in the canvas. Another advice is to keep your blocks' [Component Definition] as light as possible, if you're defining a lot of redundent properties, probably it makes sense to create another dedicated component, this might reduce the size of your project JSON file. Here an example:
Here we're reusing the same component multiple times with the same set of properties (just an example, makes more sense with composed content of components), this can be reduced to something like this.
```js
// Your components
editor.Components.addType('my-cmp', { ... });
editor.Components.addType('my-cmp-alt', {
extend: 'my-cmp',
model: {
defaults: {
prop1: 'value1-EXT',
prop2: 'value2-EXT'
}
}
});
// Your blocks
[
{ ..., content: { type: 'my-cmp-alt' } }
{ ..., content: { type: 'my-cmp-alt' } }
{ ..., content: { type: 'my-cmp-alt' } }
]
```
### HTML strings
Using HTML strings as `content` is not wrong, in some cases you don't need the finest control over components and want to leave the user full freedom on template composition (eg. static site builder editor with HTML copy-pasted from some framework like [Tailwind Components](https://tailwindcomponents.com/))
```js
// Your block
{
// ...
content: `<divclass="el-X">
<divclass="el-Y el-A">Element A</div>
<divclass="el-Y el-B">Element B</div>
<divclass="el-Y el-C">Element C</div>
</div>`
}
```
In such a case, all rendered elements will be converted to the best suited default component (eg. `.el-Y` elements will be treated like `text` components). The user will be able to style and drag them with no particular restrictions.
Thanks to Components' [isComponet](http://localhost:8081/docs/modules/Components.html#define-custom-component-type) feature (executed post parsing), you're still able to bind your rendered elements to components and enforce an extra logic. Here an example how you would enforce all `.el-Y` elements to be placed only inside `.el-X` one, without touching any part of the original HTML used in the `content`.
```js
editor.Components.addType('cmp-Y', {
// Detect '.el-Y' elements
isComponent: el => el.classList?.contains('el-Y'),
model: {
defaults: {
name: 'Component Y', // Simple custom name
draggable: '.el-X', // Add `draggable` logic
}
}
});
```
## Important caveats
::: danger Read carefully
:::
### Avoid non serializable properties
Don't put non serializable properties, like functions, in your blocks, keep them only in your components.
```js
// Your block
{
content: {
type: 'my-cmp',
script() {...},
},
}
```
This will work, but if you try to save and reload a stored project, those will disappear.
## DONT PUT IDS in your content
The difference between components and blocks: The component is more atomic, so a single image, a text box or a map is a component. The block is what the end user will drag inside the canvas, so it could contain a single image (single Component) or the entire section like, for example, the footer with a lot of components inside (texts, images, inputs, etc).
Check out the [Components] page to see the list of built-in components and how to create your own.