Free and Open source Web Builder Framework. Next generation tool for building templates without coding
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

573 lines
140 KiB

<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Component Manager | GrapesJS</title>
<meta name="generator" content="VuePress 1.9.10">
<link rel="icon" href="/docs/logo-icon.png">
<link rel="stylesheet" href="https://grapesjs.com/stylesheets/grapes.min.css?v0.21.10">
<script src="https://grapesjs.com/js/grapes.min.js?v0.21.10"></script>
<meta name="description" content="GrapesJS documentation">
<link rel="preload" href="/docs/assets/css/0.styles.c7ff573f.css" as="style"><link rel="preload" href="/docs/assets/js/app.7cba500a.js" as="script"><link rel="preload" href="/docs/assets/js/4.0070552e.js" as="script"><link rel="preload" href="/docs/assets/js/2.6fefd022.js" as="script"><link rel="preload" href="/docs/assets/js/1.d23e9fed.js" as="script"><link rel="preload" href="/docs/assets/js/85.c70a27f1.js" as="script"><link rel="prefetch" href="/docs/assets/js/12.fcd6c1b3.js"><link rel="prefetch" href="/docs/assets/js/13.f8ba6288.js"><link rel="prefetch" href="/docs/assets/js/14.37d1e434.js"><link rel="prefetch" href="/docs/assets/js/15.6e77df13.js"><link rel="prefetch" href="/docs/assets/js/16.c5f433ca.js"><link rel="prefetch" href="/docs/assets/js/17.de56d7c2.js"><link rel="prefetch" href="/docs/assets/js/18.bf39ac98.js"><link rel="prefetch" href="/docs/assets/js/19.ca87c57f.js"><link rel="prefetch" href="/docs/assets/js/20.68039d84.js"><link rel="prefetch" href="/docs/assets/js/21.2b429912.js"><link rel="prefetch" href="/docs/assets/js/22.27b0a8c5.js"><link rel="prefetch" href="/docs/assets/js/23.a6d68e8d.js"><link rel="prefetch" href="/docs/assets/js/24.74960541.js"><link rel="prefetch" href="/docs/assets/js/25.ca71342f.js"><link rel="prefetch" href="/docs/assets/js/26.33a13a48.js"><link rel="prefetch" href="/docs/assets/js/27.54f6b393.js"><link rel="prefetch" href="/docs/assets/js/28.cf1f128d.js"><link rel="prefetch" href="/docs/assets/js/29.5888c207.js"><link rel="prefetch" href="/docs/assets/js/3.4e94790f.js"><link rel="prefetch" href="/docs/assets/js/30.bace5f23.js"><link rel="prefetch" href="/docs/assets/js/31.2b0fa15d.js"><link rel="prefetch" href="/docs/assets/js/32.fdf463ac.js"><link rel="prefetch" href="/docs/assets/js/33.a739af41.js"><link rel="prefetch" href="/docs/assets/js/34.27801365.js"><link rel="prefetch" href="/docs/assets/js/35.55be1c25.js"><link rel="prefetch" href="/docs/assets/js/36.78a4b7a9.js"><link rel="prefetch" href="/docs/assets/js/37.a1d1286c.js"><link rel="prefetch" href="/docs/assets/js/38.7f94984b.js"><link rel="prefetch" href="/docs/assets/js/39.bae8130f.js"><link rel="prefetch" href="/docs/assets/js/40.d641c435.js"><link rel="prefetch" href="/docs/assets/js/41.2f0da2d4.js"><link rel="prefetch" href="/docs/assets/js/42.a0743242.js"><link rel="prefetch" href="/docs/assets/js/43.8460a28b.js"><link rel="prefetch" href="/docs/assets/js/44.943c0253.js"><link rel="prefetch" href="/docs/assets/js/45.aafa45da.js"><link rel="prefetch" href="/docs/assets/js/46.ad246b82.js"><link rel="prefetch" href="/docs/assets/js/47.b412adfe.js"><link rel="prefetch" href="/docs/assets/js/48.af9cac86.js"><link rel="prefetch" href="/docs/assets/js/49.86ad40ac.js"><link rel="prefetch" href="/docs/assets/js/5.08dc74a9.js"><link rel="prefetch" href="/docs/assets/js/50.f7509701.js"><link rel="prefetch" href="/docs/assets/js/51.8c42f1c6.js"><link rel="prefetch" href="/docs/assets/js/52.82b56909.js"><link rel="prefetch" href="/docs/assets/js/53.5f6601a1.js"><link rel="prefetch" href="/docs/assets/js/54.e8a69f95.js"><link rel="prefetch" href="/docs/assets/js/55.22891dc5.js"><link rel="prefetch" href="/docs/assets/js/56.f7e9921e.js"><link rel="prefetch" href="/docs/assets/js/57.578f14f1.js"><link rel="prefetch" href="/docs/assets/js/58.64b9e09c.js"><link rel="prefetch" href="/docs/assets/js/59.135e8739.js"><link rel="prefetch" href="/docs/assets/js/6.3a6e1ed3.js"><link rel="prefetch" href="/docs/assets/js/60.c21dfd9f.js"><link rel="prefetch" href="/docs/assets/js/61.c49c5b1e.js"><link rel="prefetch" href="/docs/assets/js/62.ce5bed3d.js"><link rel="prefetch" href="/docs/assets/js/63.3ee6f39c.js"><link rel="prefetch" href="/docs/assets/js/64.b439d27f.js"><link rel="prefetch" href="/docs/assets/js/65.ee472a88.js"><link rel="prefetch" href="/docs/assets/js/66.becd0d7a.js"><link rel="prefetch" href="/docs/assets/js/67.166cf34e.js"><link rel="prefetch" href="/docs/assets/js/68.36615226.js"><link rel="prefetch" href="/docs/assets/js/69.9a5913c7.js"><link rel="prefetch" href="/docs/assets/js/7.b99a3113.js"><link rel="prefetch" href="/docs/assets/js/70.8663a867.js"><link rel="prefetch" href="/docs/assets/js/71.8b580dcf.js"><link rel="prefetch" href="/docs/assets/js/72.355b7953.js"><link rel="prefetch" href="/docs/assets/js/73.b9ad99cd.js"><link rel="prefetch" href="/docs/assets/js/74.517d9902.js"><link rel="prefetch" href="/docs/assets/js/75.183f30c2.js"><link rel="prefetch" href="/docs/assets/js/76.894100bc.js"><link rel="prefetch" href="/docs/assets/js/77.a896626f.js"><link rel="prefetch" href="/docs/assets/js/78.a8d38215.js"><link rel="prefetch" href="/docs/assets/js/79.d0ad637c.js"><link rel="prefetch" href="/docs/assets/js/8.c0e09a5e.js"><link rel="prefetch" href="/docs/assets/js/80.43bf5b47.js"><link rel="prefetch" href="/docs/assets/js/81.a3f44150.js"><link rel="prefetch" href="/docs/assets/js/82.514bee1c.js"><link rel="prefetch" href="/docs/assets/js/83.288e8f5d.js"><link rel="prefetch" href="/docs/assets/js/84.76c28d97.js"><link rel="prefetch" href="/docs/assets/js/86.d1d289b7.js"><link rel="prefetch" href="/docs/assets/js/87.bced23ab.js"><link rel="prefetch" href="/docs/assets/js/88.f0049b73.js"><link rel="prefetch" href="/docs/assets/js/89.c2ba01c2.js"><link rel="prefetch" href="/docs/assets/js/9.6121e0b4.js"><link rel="prefetch" href="/docs/assets/js/90.529090e5.js"><link rel="prefetch" href="/docs/assets/js/91.dd59134d.js"><link rel="prefetch" href="/docs/assets/js/92.d3e7c08c.js"><link rel="prefetch" href="/docs/assets/js/93.a12b0826.js"><link rel="prefetch" href="/docs/assets/js/94.036e5ed0.js"><link rel="prefetch" href="/docs/assets/js/vendors~docsearch.0da9b1d4.js">
<link rel="stylesheet" href="/docs/assets/css/0.styles.c7ff573f.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/docs/" class="home-link router-link-active"><img src="/docs/logo.png" alt="GrapesJS" class="logo"> <span class="site-name can-hide">GrapesJS</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/docs/" class="nav-link">
Docs
</a></div><div class="nav-item"><a href="/docs/api/" class="nav-link">
API Reference
</a></div><div class="nav-item"><a href="https://opencollective.com/grapesjs" target="_blank" rel="noopener noreferrer" class="nav-link external">
Support Us
<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="https://twitter.com/grapesjs" target="_blank" rel="noopener noreferrer" class="nav-link external">
Twitter
<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div> <a href="https://github.com/artf/grapesjs" target="_blank" rel="noopener noreferrer" class="repo-link">
GitHub
<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/docs/" class="nav-link">
Docs
</a></div><div class="nav-item"><a href="/docs/api/" class="nav-link">
API Reference
</a></div><div class="nav-item"><a href="https://opencollective.com/grapesjs" target="_blank" rel="noopener noreferrer" class="nav-link external">
Support Us
<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="https://twitter.com/grapesjs" target="_blank" rel="noopener noreferrer" class="nav-link external">
Twitter
<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div> <a href="https://github.com/artf/grapesjs" target="_blank" rel="noopener noreferrer" class="repo-link">
GitHub
<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav> <div id="native-carbon" class="carbon-ads"></div> <ul class="sidebar-links"><li><a href="/docs/" aria-current="page" class="sidebar-link">Introduction</a></li><li><a href="/docs/getting-started.html" class="sidebar-link">Getting Started</a></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>Modules</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/docs/modules/Components.html" aria-current="page" class="active sidebar-link">Components</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/docs/modules/Components.html#how-components-work" class="sidebar-link">How Components work?</a></li><li class="sidebar-sub-header"><a href="/docs/modules/Components.html#built-in-component-types" class="sidebar-link">Built-in Component Types</a></li><li class="sidebar-sub-header"><a href="/docs/modules/Components.html#define-custom-component-type" class="sidebar-link">Define Custom Component Type</a></li><li class="sidebar-sub-header"><a href="/docs/modules/Components.html#update-component-type" class="sidebar-link">Update Component Type</a></li><li class="sidebar-sub-header"><a href="/docs/modules/Components.html#lifecycle-hooks" class="sidebar-link">Lifecycle Hooks</a></li><li class="sidebar-sub-header"><a href="/docs/modules/Components.html#components-css" class="sidebar-link">Components &amp; CSS</a></li><li class="sidebar-sub-header"><a href="/docs/modules/Components.html#components-js" class="sidebar-link">Components &amp; JS</a></li><li class="sidebar-sub-header"><a href="/docs/modules/Components.html#tips" class="sidebar-link">Tips</a></li></ul></li><li><a href="/docs/modules/Components-js.html" class="sidebar-link">Components &amp; JS</a></li><li><a href="/docs/modules/Traits.html" class="sidebar-link">Traits</a></li><li><a href="/docs/modules/Blocks.html" class="sidebar-link">Blocks</a></li><li><a href="/docs/modules/Assets.html" class="sidebar-link">Assets</a></li><li><a href="/docs/modules/Commands.html" class="sidebar-link">Commands</a></li><li><a href="/docs/modules/I18n.html" class="sidebar-link">I18n</a></li><li><a href="/docs/modules/Selectors.html" class="sidebar-link">Selectors</a></li><li><a href="/docs/modules/Layers.html" class="sidebar-link">Layers</a></li><li><a href="/docs/modules/Pages.html" class="sidebar-link">Pages</a></li><li><a href="/docs/modules/Style-manager.html" class="sidebar-link">Style Manager</a></li><li><a href="/docs/modules/Storage.html" class="sidebar-link">Storage Manager</a></li><li><a href="/docs/modules/Modal.html" class="sidebar-link">Modal</a></li><li><a href="/docs/modules/Plugins.html" class="sidebar-link">Plugins</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>Guides</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/docs/guides/Replace-Rich-Text-Editor.html" class="sidebar-link">Replace Rich Text Editor</a></li><li><a href="/docs/guides/Custom-CSS-parser.html" class="sidebar-link">Use Custom CSS Parser</a></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="component-manager"><a href="#component-manager" class="header-anchor">#</a> Component Manager</h1> <p>The Component is a base element of the template. It might be something simple and atomic like an image or a text box, but also complex structures, more probably composed by other components, like sections or pages. The concept of the component was made to allow the developer to bind different behaviors to different elements. For example, opening the Asset Manager on double click of the image is a custom behavior bound to that particular type of element.</p> <div class="custom-block warning"><p class="custom-block-title">WARNING</p> <p>This guide is referring to GrapesJS v0.15.8 or higher</p></div> <p></p><div class="table-of-contents"><ul><li><a href="#how-components-work">How Components work?</a><ul><li><a href="#component-definition">Component Definition</a></li><li><a href="#component-recognition-and-component-type-stack">Component Recognition and Component Type Stack</a></li><li><a href="#component-instance">Component instance</a></li><li><a href="#component-rendering">Component rendering</a></li></ul></li><li><a href="#built-in-component-types">Built-in Component Types</a></li><li><a href="#define-custom-component-type">Define Custom Component Type</a><ul><li><a href="#iscomponent">isComponent</a></li><li><a href="#model">Model</a></li><li><a href="#view">View</a></li></ul></li><li><a href="#update-component-type">Update Component Type</a><ul><li><a href="#extend-component-type">Extend Component Type</a></li><li><a href="#extend-parent-functions">Extend parent functions</a></li></ul></li><li><a href="#lifecycle-hooks">Lifecycle Hooks</a></li><li><a href="#components-css">Components &amp; CSS</a><ul><li><a href="#external-css">External CSS</a></li></ul></li><li><a href="#components-js">Components &amp; JS</a></li><li><a href="#tips">Tips</a><ul><li><a href="#jsx-syntax">JSX syntax</a></li></ul></li></ul></div><p></p> <h2 id="how-components-work"><a href="#how-components-work" class="header-anchor">#</a> How Components work?</h2> <p>Let's see in detail how components work by looking at all the steps from adding an HTML string to the editor.</p> <div class="custom-block tip"><p class="custom-block-title">TIP</p> <p>All the following snippets can be run directly in console from the <a href="https://grapesjs.com/demo.html" target="_blank" rel="noopener noreferrer">main demo<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></div> <p>This is how we can add new components to the canvas:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// Append components directly to the canvas</span>
editor<span class="token punctuation">.</span><span class="token function">addComponents</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;div&gt;
&lt;img src=&quot;https://path/image&quot; /&gt;
&lt;span title=&quot;foo&quot;&gt;Hello world!!!&lt;/span&gt;
&lt;/div&gt;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// or into some, already defined, component.</span>
<span class="token comment">// For instance, appending to a selected component would be:</span>
editor<span class="token punctuation">.</span><span class="token function">getSelected</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;div&gt;...</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Actually, editor.addComponents is an alias of...</span>
editor<span class="token punctuation">.</span><span class="token function">getWrapper</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;div&gt;...</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><div class="custom-block tip"><p class="custom-block-title">TIP</p> <p>If you need to append a component at a specific position, you can use <code>at</code> option. So, to add a component on top of all others (in the same collection) you would use</p> <div class="language-js extra-class"><pre class="language-js"><code>component<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">'&lt;div&gt;...'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">at</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p>or in the middle</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token punctuation">{</span> length <span class="token punctuation">}</span> <span class="token operator">=</span> component<span class="token punctuation">.</span><span class="token function">components</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
component<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">'&lt;div&gt;...'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">at</span><span class="token operator">:</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>length <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div></div> <h3 id="component-definition"><a href="#component-definition" class="header-anchor">#</a> Component Definition</h3> <p>In the first step, the HTML string is parsed and transformed to what is called <strong>Component Definition</strong>, so the result of the input above would be:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token punctuation">{</span>
<span class="token literal-property property">tagName</span><span class="token operator">:</span> <span class="token string">'div'</span><span class="token punctuation">,</span>
<span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span>
<span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'image'</span><span class="token punctuation">,</span>
<span class="token literal-property property">attributes</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">src</span><span class="token operator">:</span> <span class="token string">'https://path/image'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token literal-property property">tagName</span><span class="token operator">:</span> <span class="token string">'span'</span><span class="token punctuation">,</span>
<span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span>
<span class="token literal-property property">attributes</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'foo'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span>
<span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'textnode'</span><span class="token punctuation">,</span>
<span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">'Hello world!!!'</span>
<span class="token punctuation">}</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span>
<span class="token punctuation">]</span>
<span class="token punctuation">}</span>
</code></pre></div><p>The real <strong>Component Definition</strong> would be a little bit bigger so we've reduced the JSON for the sake of simplicity.</p> <p>You might notice the result is similar to what is generally called a <strong>Virtual DOM</strong>, a lightweight representation of the DOM element. This actually helps the editor to keep track of the state of our elements and make performance-friendly changes/updates.
The meaning of properties like <code>tagName</code>, <code>attributes</code> and <code>components</code> are quite obvious, but what about <code>type</code>?! This particular property specifies the <strong>Component Type</strong> of our <strong>Component Definition</strong> (you check the list of default components <a href="#built-in-component-types">below</a>) and if it's omitted, the default one will be used <code>type: 'default'</code>.
At this point, a good question would be, how the editor assigns those types by starting from a simple HTML string? This step is identified as <strong>Component Recognition</strong> and it's explained in detail in the next paragraph.</p> <h3 id="component-recognition-and-component-type-stack"><a href="#component-recognition-and-component-type-stack" class="header-anchor">#</a> Component Recognition and Component Type Stack</h3> <p>As we mentioned before, when you pass an HTML string as a component to the editor, that string is parsed and compiled to the <a href="#component-definition">Component Definition</a> with a new <code>type</code> property. To understand what <code>type</code> should be assigned, for each parsed HTML Element, the editor iterates over all the defined components, called <strong>Component Type Stack</strong>, and checks via <code>isComponent</code> method (we will see it later) if that component type is appropriate for that element. The Component Type Stack is just a simple array of component types but what matters is the order of those types. Any new added custom <strong>Component Type</strong> (we'll see later how to create them) goes on top of the Component Type Stack and each element returned from the parser iterates the stack from top to bottom (the last element of the stack is the <code>default</code> one), the iteration stops once one of the component returns a truthy value from the <code>isComponent</code> method.</p> <img src="/docs/component-type-stack.svg" class="img-ctr"> <div class="custom-block tip"><p class="custom-block-title">TIP</p> <p>If you're importing big string chunks of HTML code you might want to improve the performances by skipping the parsing and the component recognition steps by passing directly Component Definition objects or using the JSX syntax.
Read <a href="#setup-jsx-syntax">here</a> about how to setup JSX syntax parser</p></div> <h3 id="component-instance"><a href="#component-instance" class="header-anchor">#</a> Component instance</h3> <p>Once the <strong>Component Definition</strong> is ready and the type is assigned, the <a href="/docs/api/component.html">Component</a> instance can be created (known also as the <strong>Model</strong>). Let's step back to our previous example with the HTML string, the result of the <code>append</code> method is an array of added components.</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> component <span class="token operator">=</span> editor<span class="token punctuation">.</span><span class="token function">addComponents</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;div&gt;
&lt;img src=&quot;https://path/image&quot; /&gt;
&lt;span title=&quot;foo&quot;&gt;Hello world!!!&lt;/span&gt;
&lt;/div&gt;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre></div><p>The Component instance contains properties and methods which allows you to obtain its data and change them.
You can read properties with the <code>get</code> method, like, for example, the <code>type</code></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> componentType <span class="token operator">=</span> component<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'type'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// eg. 'image'</span>
</code></pre></div><p>and to update properties you'd use <code>set</code>, which might change the way a component behaves in the canvas.</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// Make the component not draggable</span>
component<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">'draggable'</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>You can also use methods like <code>getAttributes</code>, <code>setAttributes</code>, <code>components</code>, etc.</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> innerComponents <span class="token operator">=</span> component<span class="token punctuation">.</span><span class="token function">components</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
innerComponents<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">comp</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>comp<span class="token punctuation">.</span><span class="token function">toHTML</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Update component content</span>
component<span class="token punctuation">.</span><span class="token function">components</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;div&gt;Component 1&lt;/div&gt;&lt;div&gt;Component 2&lt;/div&gt;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Each component can define its own properties and methods but all of them will always extend, at least, the <code>default</code> one (then you will see how to create new custom components and how to extend the already defined) so it's good to check the <a href="/docs/api/component.html">Component API</a> to see all available properties and methods.</p> <p>The <strong>main purpose of the Component</strong> 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</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> componentHTML <span class="token operator">=</span> component<span class="token punctuation">.</span><span class="token function">toHTML</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>This will return a string containing the HTML of the component and all of its children.
The component implements also <code>toJSON</code> methods so you can get its JSON structure in this way</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>component<span class="token punctuation">)</span>
</code></pre></div><div class="custom-block tip"><p class="custom-block-title">TIP</p> <p>For storing/loading all the components you should rely on the <a href="/docs/modules/storage.html">Storage Manager</a></p></div> <p>So, the <strong>Component instance</strong> is responsible for the <strong>final data</strong> (eg. HTML, JSON) of your templates. If you need, for example, to update/add some attribute in the HTML you need to update its component (eg. <code>component.addAttributes({ title: 'Title added' })</code>), so the Component/Model is your <strong>Source of Truth</strong>.</p> <h3 id="component-rendering"><a href="#component-rendering" class="header-anchor">#</a> Component rendering</h3> <p>Another important part of components is how they are rendered in the <strong>canvas</strong>, this aspect is handled by its <strong>View</strong>. It has nothing to do with the <strong>final HTML data</strong>, you can return a big <code>&lt;div&gt;...&lt;/div&gt;</code> string as HTML of your component but render it as a simple image in the canvas (think about placeholders for complex/dynamic data).</p> <p>By default, the view of components is automatically synced with the data of its models (you can't have a View without a Model). If you update the attribute of the component or append a new one as a child, the view will render it in the canvas.</p> <p>Unfortunately, sometimes, you might need some additional logic to handle better the component result. Think about allowing a user build its <code>&lt;table&gt;</code> element, for this specific case you might want to add custom buttons in the canvas, so it'd be easier adding/removing columns/rows. To handle those cases you can rely on the View, where you can add additional DOM component, attach events, etc. All of this will be completely unrelated with the final HTML of the <code>&lt;table&gt;</code> (the result the user would expect) as it handled by the Model.
Once the component is rendered you can always access its View and the DOM element.</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> component <span class="token operator">=</span> editor<span class="token punctuation">.</span><span class="token function">getSelected</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Get the View</span>
<span class="token keyword">const</span> view <span class="token operator">=</span> component<span class="token punctuation">.</span><span class="token function">getView</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Get the DOM element</span>
<span class="token keyword">const</span> el <span class="token operator">=</span> component<span class="token punctuation">.</span><span class="token function">getEl</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Generally, the View is something you wouldn't need to change as the default one handles already the sync with the Model but in case you'd need more control over elements (eg. custom UI in canvas) you'll probably need to create a custom component type and extend the default View with your logic. We'll see later how to create custom Component Types.</p> <p>So far we have seen the core concept behind Components and how they work. The <strong>Model/Component</strong> is the <strong>source of truth</strong> for the final code of templates (eg. the HTML export relies on it) and the <strong>View/ComponentView</strong> is what is used by the editor to <strong>preview our components</strong> to users in the canvas.</p> <h2 id="built-in-component-types"><a href="#built-in-component-types" class="header-anchor">#</a> Built-in Component Types</h2> <p>Here below you can see the list of built-in component types, ordered by their position in the <strong>Component Type Stack</strong></p> <ul><li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentTableCell.ts" target="_blank" rel="noopener noreferrer"><code>cell</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Component for handle <code>&lt;td&gt;</code> and <code>&lt;th&gt;</code> elements</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentTableRow.ts" target="_blank" rel="noopener noreferrer"><code>row</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Component for handle <code>&lt;tr&gt;</code> elements</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentTable.ts" target="_blank" rel="noopener noreferrer"><code>table</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Component for handle <code>&lt;table&gt;</code> elements</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentTableHead.ts" target="_blank" rel="noopener noreferrer"><code>thead</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Component for handle <code>&lt;thead&gt;</code> elements</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentTableBody.ts" target="_blank" rel="noopener noreferrer"><code>tbody</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Component for handle <code>&lt;tbody&gt;</code> elements</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentTableFoot.ts" target="_blank" rel="noopener noreferrer"><code>tfoot</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Component for handle <code>&lt;tfoot&gt;</code> elements</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentMap.ts" target="_blank" rel="noopener noreferrer"><code>map</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Component for handle <code>&lt;a&gt;</code> elements</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentLink.ts" target="_blank" rel="noopener noreferrer"><code>link</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Component for handle <code>&lt;a&gt;</code> elements</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentLabel.ts" target="_blank" rel="noopener noreferrer"><code>label</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Component for handle properly <code>&lt;label&gt;</code> elements</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentVideo.ts" target="_blank" rel="noopener noreferrer"><code>video</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Component for videos</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentImage.ts" target="_blank" rel="noopener noreferrer"><code>image</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Component for images</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentScript.ts" target="_blank" rel="noopener noreferrer"><code>script</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Component for handle <code>&lt;script&gt;</code> elements</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentSvg.ts" target="_blank" rel="noopener noreferrer"><code>svg</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Component for handle SVG elements</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentComment.ts" target="_blank" rel="noopener noreferrer"><code>comment</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Component for comments (might be useful for email editors)</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentTextNode.ts" target="_blank" rel="noopener noreferrer"><code>textnode</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - Similar to the textnode in DOM definition, so a text element without a tag element.</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentText.ts" target="_blank" rel="noopener noreferrer"><code>text</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - A simple text component that can be edited inline</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/ComponentWrapper.ts" target="_blank" rel="noopener noreferrer"><code>wrapper</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> - The canvas need to contain a root component, a wrapper, this component was made to identify it</li> <li><a href="https://github.com/GrapesJS/grapesjs/blob/dev/src/dom_components/model/Component.ts" target="_blank" rel="noopener noreferrer"><code>default</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> Default base component</li></ul> <h2 id="define-custom-component-type"><a href="#define-custom-component-type" class="header-anchor">#</a> Define Custom Component Type</h2> <p>Now that we know how components work, we can start exploring the process of creating custom <strong>Component Types</strong>.</p> <p><u>The first rule of defining new component types is to place the code inside a plugin</u>. This is necessary if you want to load your custom types at the beginning, before any component initialization (eg. a template loaded from DB). The plugin is loaded before component fetch (eg. in case of Storage use) so it's a perfect place to define component types.</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token function-variable function">myNewComponentTypes</span> <span class="token operator">=</span> <span class="token parameter">editor</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
editor<span class="token punctuation">.</span>DomComponents<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token comment">/* API for component type definition */</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> editor <span class="token operator">=</span> grapesjs<span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">container</span> <span class="token operator">:</span> <span class="token string">'#gjs'</span><span class="token punctuation">,</span>
<span class="token comment">// ...</span>
<span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span> myNewComponentTypes <span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Let's say we want to make the editor understand and handle better <code>&lt;input&gt;</code> elements. This is how we would start defining our new component type</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>DomComponents<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'my-input-type'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token comment">// Make the editor understand when to bind `my-input-type`</span>
<span class="token function-variable function">isComponent</span><span class="token operator">:</span> <span class="token parameter">el</span> <span class="token operator">=&gt;</span> el<span class="token punctuation">.</span>tagName <span class="token operator">===</span> <span class="token string">'INPUT'</span><span class="token punctuation">,</span>
<span class="token comment">// Model definition</span>
<span class="token literal-property property">model</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token comment">// Default properties</span>
<span class="token literal-property property">defaults</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">tagName</span><span class="token operator">:</span> <span class="token string">'input'</span><span class="token punctuation">,</span>
<span class="token literal-property property">draggable</span><span class="token operator">:</span> <span class="token string">'form, form *'</span><span class="token punctuation">,</span> <span class="token comment">// Can be dropped only inside `form` elements</span>
<span class="token literal-property property">droppable</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token comment">// Can't drop other elements inside</span>
<span class="token literal-property property">attributes</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">// Default attributes</span>
<span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span>
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'default-name'</span><span class="token punctuation">,</span>
<span class="token literal-property property">placeholder</span><span class="token operator">:</span> <span class="token string">'Insert text here'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token literal-property property">traits</span><span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token string">'name'</span><span class="token punctuation">,</span>
<span class="token string">'placeholder'</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'checkbox'</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'required'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>With this code, the editor will be able to understand simple text <code>&lt;input&gt;</code>s, assign default attributes and show some trait for a better attribute handling.</p> <div class="custom-block tip"><p class="custom-block-title">TIP</p> <p>To understand better how Traits work you should read its <a href="/docs/modules/Traits.html">dedicated page</a> but we highly suggest to read it after you've finished reading this one</p></div> <h3 id="iscomponent"><a href="#iscomponent" class="header-anchor">#</a> isComponent</h3> <p>Let's see in detail what we have done so far. The first thing to notice is the <code>isComponent</code> function, we have already mentioned its usage in <a href="#component-recognition-and-component-type-stack">this</a> section and we need it to make the editor understand <code>&lt;input&gt;</code> during the component recognition step.
It receives only the <code>el</code> argument, which is the parsed HTMLElement node and expects a truthy value in case the element satisfies your logic condition. So, if we add this HTML string as component</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// ...after editor initialization</span>
editor<span class="token punctuation">.</span><span class="token function">addComponents</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;input name=&quot;my-test&quot; title=&quot;hello&quot;/&gt;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
</code></pre></div><p>The resultant Component Definition will be</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token punctuation">{</span>
<span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'my-input-type'</span><span class="token punctuation">,</span>
<span class="token literal-property property">attributes</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'my-test'</span><span class="token punctuation">,</span>
<span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'hello'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre></div><p>If you need you can also customize the resultant Component Definition by returning an object as the result:</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>DomComponents<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'my-input-type'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token function-variable function">isComponent</span><span class="token operator">:</span> <span class="token parameter">el</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>el<span class="token punctuation">.</span>tagName <span class="token operator">===</span> <span class="token string">'INPUT'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// You should explicitly declare the type of your resultant</span>
<span class="token comment">// object, otherwise the `default` one will be used</span>
<span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'my-input-type'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token comment">/* some other condition */</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
result<span class="token punctuation">.</span>attributes <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Hi'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> result<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><div class="custom-block danger"><p class="custom-block-title">DANGER</p> <p>Keep the <code>isComponent</code> function as simple as possible</p></div> <p><strong>Be aware</strong> that this method will probably receive ANY parsed element from your canvas (eg. on load or on add) and not all the nodes have the same interface (eg. properties/methods).
If you do this:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// ...</span>
<span class="token comment">// Print elements</span>
<span class="token function-variable function">isComponent</span><span class="token operator">:</span> <span class="token parameter">el</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>el<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> el<span class="token punctuation">.</span>tagName <span class="token operator">===</span> <span class="token string">'INPUT'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// ...</span>
editor<span class="token punctuation">.</span><span class="token function">addComponents</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;div&gt;
I'm a text node
&lt;!-- I'm a comment node --&gt;
&lt;img alt=&quot;Image here&quot;/&gt;
&lt;input/&gt;
&lt;/div&gt;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>You will see printing all the nodes, so doing something like this <code>el.getAttribute('...')</code> in your <code>isComponent</code> (which will work on the <code>div</code> but not on the <code>text node</code>), without an appropriate check, will break the code.</p> <p>It's also important to understand that <code>isComponent</code> is executed only if the parsing is required (eg. by adding components as HTML string or initializing the editor with <code>fromElement</code>). In case the type is already defined, there is no need for the <code>isComponent</code> to be executed.
Let's see some examples:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// isComponent will be executed on some-element</span>
editor<span class="token punctuation">.</span><span class="token function">addComponents</span><span class="token punctuation">(</span><span class="token string">'&lt;some-element&gt;...&lt;/some-element&gt;'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// isComponent WON'T be executed on OBJECTS</span>
<span class="token comment">// If the object has no `type` key, the `default` one will be used</span>
editor<span class="token punctuation">.</span><span class="token function">addComponents</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'some-component'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// isComponent WON'T be executed as we're forcing the type</span>
editor<span class="token punctuation">.</span><span class="token function">addComponents</span><span class="token punctuation">(</span><span class="token string">'&lt;some-element data-gjs-type=&quot;some-component&quot;&gt;...'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>If you define the Component Type without using <code>isComponent</code>, the only way for the editor to see that component will be with an explicitly declared type (via an object <code>{ type: '...' }</code> or using <code>data-gjs-type</code>).</p> <h3 id="model"><a href="#model" class="header-anchor">#</a> Model</h3> <p>Now that we got how <code>isComponent</code> works we can start to explore the <code>model</code> property.
The <code>model</code> is probably the one you'll use the most as is what is used for the description of your component and the first thing you can see is its <code>defaults</code> key which just stands for <em>default component properties</em> and it reflects the already described <a href="#component-definition">Component Definition</a></p> <p>The model defines also what you will see as the resultant HTML (the export code) and you've probably noticed the use of <code>tagName</code> (if not specified the <code>div</code> will be used) and <code>attributes</code> properties on the model.</p> <p>One another important property (not used in our input component integration because <code>&lt;input/&gt;</code> doesn't need it) might be <code>components</code>, which defines default internal components</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token literal-property property">defaults</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">tagName</span><span class="token operator">:</span> <span class="token string">'div'</span><span class="token punctuation">,</span>
<span class="token literal-property property">attributes</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Hello'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// Can be a string</span>
<span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
&lt;h1&gt;Header test&lt;/h1&gt;
&lt;p&gt;Paragraph test&lt;/p&gt;
</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
<span class="token comment">// A component definition</span>
<span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">tagName</span><span class="token operator">:</span> <span class="token string">'h1'</span><span class="token punctuation">,</span>
<span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token string">'Header test'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// Array of strings/component definitions</span>
<span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span>
<span class="token literal-property property">tagName</span><span class="token operator">:</span> <span class="token string">'h1'</span><span class="token punctuation">,</span>
<span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token string">'Header test'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">'&lt;p&gt;Paragraph test&lt;/p&gt;'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token comment">// Or a function, which get as an argument the current</span>
<span class="token comment">// model and expects as the return one of the possible</span>
<span class="token comment">// values described above</span>
<span class="token function-variable function">components</span><span class="token operator">:</span> <span class="token parameter">model</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;h1&gt;Header test: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>model<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'type'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/h1&gt;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre></div><h4 id="read-and-update-the-model"><a href="#read-and-update-the-model" class="header-anchor">#</a> Read and update the model</h4> <p>You can read and update the model properties wherever you have the reference to it. Here some references to the most useful API</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// let's use the selected component</span>
<span class="token keyword">const</span> modelComponent <span class="token operator">=</span> editor<span class="token punctuation">.</span><span class="token function">getSelected</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Get all the model properties</span>
<span class="token keyword">const</span> props <span class="token operator">=</span> modelComponent<span class="token punctuation">.</span><span class="token function">props</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Get a single property</span>
<span class="token keyword">const</span> tagName <span class="token operator">=</span> modelComponent<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'tagName'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Update a single property</span>
modelComponent<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">'tagName'</span><span class="token punctuation">,</span> <span class="token string">'...'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Update multiple properties</span>
modelComponent<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">tagName</span><span class="token operator">:</span> <span class="token string">'...'</span><span class="token punctuation">,</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Some helpers</span>
<span class="token comment">// Get all attributes</span>
<span class="token keyword">const</span> attrs <span class="token operator">=</span> modelComponent<span class="token punctuation">.</span><span class="token function">getAttributes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Add attributes</span>
modelComponent<span class="token punctuation">.</span><span class="token function">addAttributes</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Test'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Replace all attributes</span>
modelComponent<span class="token punctuation">.</span><span class="token function">setAttributes</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Test'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Get the collection of all inner components</span>
modelComponent<span class="token punctuation">.</span><span class="token function">components</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>
<span class="token parameter">inner</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>inner<span class="token punctuation">.</span><span class="token function">props</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Update the inner content with an HTML string/Component Definitions</span>
<span class="token keyword">const</span> addedComponents <span class="token operator">=</span> modelComponent<span class="token punctuation">.</span><span class="token function">components</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;div&gt;...&lt;/div&gt;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Find components by query string</span>
modelComponent<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.query-string[example=value]</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>
<span class="token parameter">inner</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>inner<span class="token punctuation">.</span><span class="token function">props</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>You'll notice that, on any change, the component in the canvas and its export code are changing accordingly</p> <div class="custom-block tip"><p class="custom-block-title">TIP</p> <p>To know all the available methods/properties check the <a href="/docs/api/component.html">Component API</a></p></div> <h4 id="listen-to-property-changes"><a href="#listen-to-property-changes" class="header-anchor">#</a> Listen to property changes</h4> <p>If you need to accomplish some kind of action on some property change you can set up listeners in the <code>init</code> method</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>DomComponents<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'my-input-type'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token literal-property property">model</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">defaults</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token literal-property property">someprop</span><span class="token operator">:</span> <span class="token string">'initial value'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'change:someprop'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handlePropChange<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Listen to any attribute change</span>
<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'change:attributes'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleAttrChange<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Listen to title attribute change</span>
<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'change:attributes:title'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleTitleChange<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function">handlePropChange</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> someprop <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">props</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'New value of someprop: '</span><span class="token punctuation">,</span> someprop<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function">handleAttrChange</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Attributes updated: '</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttributes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function">handleTitleChange</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Attribute title updated: '</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttributes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>title<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>You'll find other lifecycle methods, like <code>init</code>, <a href="#lifecycle-hooks">below</a></p> <p>Now let's go back to our input component integration and see another useful part for the component customization</p> <h3 id="view"><a href="#view" class="header-anchor">#</a> View</h3> <p>Generally, when you create a component in GrapesJS you expect to see in the canvas the preview of what you've defined in the model. Indeed, by default, the editor does the exact thing and updates the element in the canvas when something in the model changes (eg. attributes, tag, etc.) to obtain the classic <strong>WYSIWYG</strong> (What You See Is What You Get) experience. Unfortunately, not always the simplest thing is the right one, by building components for the builder you will notice that sometimes you'll need something more:</p> <ul><li><p>You want to improve the experience of editing of the component.
A perfect example is the TextComponent, its view is enriched with a built-in RTE (Rich Text Editor) which enables the user to edit the text faster by double-clicking on it.</p> <p>So you'll probably feel a need adding actions to react on some DOM events or even custom UI elements (eg. buttons) around the component.</p></li> <li><p>The DOM representation of the component acts differently from what you'd expect, so you need to change some behavior.
An example could be a VideoComponent which, for example, is loaded from Youtube via iframe. Once the iframe is loaded, everything inside it is in a different context, the editor is not able to see it, indeed if you point your cursor on the iframe you'll interact with the video and not the editor, so you can't even select your component. To workaround this &quot;issue&quot;, in the render, we disabled the pointer interaction with the iframe and wrapped it with another element (without the wrapper the editor would select the parent component). Obviously, all of these changes have nothing to do with the final code, the result will always be a simple iframe</p></li> <li><p>You need to customize the content or fill it with some data from the server</p></li></ul> <p>For all of these cases, you can use the <code>view</code> in your Component Type Definition. The <code>&lt;input&gt;</code> component is probably not the best use case for this scenario but we'll try to cover most of the cases with an example below</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>DomComponents<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'my-input-type'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token literal-property property">model</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token literal-property property">view</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token comment">// Be default, the tag of the element is the same of the model</span>
<span class="token literal-property property">tagName</span><span class="token operator">:</span> <span class="token string">'div'</span><span class="token punctuation">,</span>
<span class="token comment">// Add easily component specific listeners with `events`</span>
<span class="token comment">// Being component specific (eg. you can't attach here listeners to window)</span>
<span class="token comment">// you don't need to care about removing them when the component is removed,</span>
<span class="token comment">// they will be managed automatically by the editor</span>
<span class="token literal-property property">events</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">click</span><span class="token operator">:</span> <span class="token string">'clickOnElement'</span><span class="token punctuation">,</span>
<span class="token comment">// You can also make use of event delegation</span>
<span class="token comment">// and listen to events bubbled from some inner element</span>
<span class="token string-property property">'dblclick .inner-el'</span><span class="token operator">:</span> <span class="token string">'innerElClick'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function">innerElClick</span><span class="token punctuation">(</span><span class="token parameter">ev</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
ev<span class="token punctuation">.</span><span class="token function">stopPropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ...</span>
<span class="token comment">// If you need you can access the model from any function in the view</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>model<span class="token punctuation">.</span><span class="token function">components</span><span class="token punctuation">(</span><span class="token string">'Update inner components'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// On init you can create listeners, like in the model, or start some other</span>
<span class="token comment">// function at the beginning</span>
<span class="token function">init</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> model <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Do something in view on model property change</span>
<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">listenTo</span><span class="token punctuation">(</span>model<span class="token punctuation">,</span> <span class="token string">'change:prop'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handlePropChange<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// If you attach listeners on outside objects remember to unbind</span>
<span class="token comment">// them in `removed` function in order to avoid memory leaks</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>onDocClick <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">onDocClick</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>onDocClick<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// Callback triggered when the element is removed from the canvas</span>
<span class="token function">removed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
document<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>onDocClick<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// Do something with the content once the element is rendered.</span>
<span class="token comment">// The DOM element is passed as `el` in the argument object,</span>
<span class="token comment">// but you can access it from any function via `this.el`</span>
<span class="token function">onRender</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> el <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> btn <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
btn<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token string">'+'</span><span class="token punctuation">;</span>
<span class="token comment">// This is just an example, AVOID adding events on inner elements,</span>
<span class="token comment">// use `events` for these cases</span>
btn<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
el<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>btn<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// Example of async content</span>
<span class="token keyword">async</span> <span class="token function">onRender</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> el<span class="token punctuation">,</span> model <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> asyncContent <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetchSomething</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">someDataFromModel</span><span class="token operator">:</span> model<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'someData'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Remember, these changes exist only inside the editor canvas</span>
<span class="token comment">// None of the DOM change is stored in your template data,</span>
<span class="token comment">// if you need to store something, update the model properties</span>
el<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>asyncContent<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="update-component-type"><a href="#update-component-type" class="header-anchor">#</a> Update Component Type</h2> <p>Updating component types is quite easy, let's see how:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> domc <span class="token operator">=</span> editor<span class="token punctuation">.</span>DomComponents<span class="token punctuation">;</span>
domc<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'some-component'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token comment">// You can update the isComponent logic or leave the one from `some-component`</span>
<span class="token comment">// isComponent: (el) =&gt; false,</span>
<span class="token comment">// Update the model, if you need</span>
<span class="token literal-property property">model</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token comment">// The `defaults` property is handled differently</span>
<span class="token comment">// and will be merged with the old `defaults`</span>
<span class="token literal-property property">defaults</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">tagName</span><span class="token operator">:</span> <span class="token string">'...'</span><span class="token punctuation">,</span> <span class="token comment">// Overrides the old one</span>
<span class="token literal-property property">someNewProp</span><span class="token operator">:</span> <span class="token string">'Hello'</span><span class="token punctuation">,</span> <span class="token comment">// Add new property</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Ovverride `init` function in `some-component`</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// Update the view, if you need</span>
<span class="token literal-property property">view</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h3 id="extend-component-type"><a href="#extend-component-type" class="header-anchor">#</a> Extend Component Type</h3> <p>Sometimes you would need to create a new type by extending another one. Just use <code>extend</code> and <code>extendView</code> indicating the component to extend.</p> <div class="language-js extra-class"><pre class="language-js"><code>comps<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'my-new-component'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token function-variable function">isComponent</span><span class="token operator">:</span> <span class="token parameter">el</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token comment">/* ... */</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token literal-property property">extend</span><span class="token operator">:</span> <span class="token string">'other-defined-component'</span><span class="token punctuation">,</span>
<span class="token literal-property property">model</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// Will extend the model from 'other-defined-component'</span>
<span class="token literal-property property">view</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// Will extend the view from 'other-defined-component'</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code>comps<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'my-new-component'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token function-variable function">isComponent</span><span class="token operator">:</span> <span class="token parameter">el</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token comment">/* ... */</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token literal-property property">extend</span><span class="token operator">:</span> <span class="token string">'other-defined-component'</span><span class="token punctuation">,</span>
<span class="token literal-property property">model</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// Will extend the model from 'other-defined-component'</span>
<span class="token literal-property property">extendView</span><span class="token operator">:</span> <span class="token string">'other-defined-component-2'</span><span class="token punctuation">,</span>
<span class="token literal-property property">view</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// Will extend the view from 'other-defined-component-2'</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h3 id="extend-parent-functions"><a href="#extend-parent-functions" class="header-anchor">#</a> Extend parent functions</h3> <p>When you need to reuse functions, from the parent you're extending, you can avoid writing this:</p> <div class="language-js extra-class"><pre class="language-js"><code>domc<span class="token punctuation">.</span><span class="token function">getType</span><span class="token punctuation">(</span><span class="token string">'parent-type'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>model<span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>by using <code>extendFn</code> and <code>extendFnView</code> options:</p> <div class="language-js extra-class"><pre class="language-js"><code>domc<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'new-type'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token literal-property property">extend</span><span class="token operator">:</span> <span class="token string">'parent-type'</span><span class="token punctuation">,</span>
<span class="token literal-property property">extendFn</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'init'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// array of model functions to extend from `parent-type`</span>
<span class="token literal-property property">model</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// do something</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>The same would be for the view by using <code>extendFnView</code></p> <div class="custom-block tip"><p class="custom-block-title">TIP</p> <p>If you need you can also get all the current component types by using <code>getTypes</code></p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>DomComponents<span class="token punctuation">.</span><span class="token function">getTypes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">compType</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>compType<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div></div> <h2 id="lifecycle-hooks"><a href="#lifecycle-hooks" class="header-anchor">#</a> Lifecycle Hooks</h2> <p>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: <strong>global</strong> and <strong>local</strong>.
You define <strong>local</strong> hooks when you create/extend a component type (usually via some <code>model</code>/<code>view</code> method) and the reason is to react to an event of that
particular component type. Instead, the <strong>global</strong> one, will be called indistinctly on any component (you listen to them via <code>editor.on</code>) and you can make
use of them for a more generic use case or also listen to them inside other components.</p> <p>Let's see below the flow of all hooks:</p> <ul><li><strong>Local hook</strong>: <code>model.init()</code> method, executed once the model of the component is initialized</li> <li><strong>Global hook</strong>: <code>component:create</code> event, called right after <code>model.init()</code>. The model is passed as an argument to the callback function.
Es. <code>editor.on('component:create', model =&gt; console.log('created', model))</code></li> <li><strong>Local hook</strong>: <code>view.init()</code> method, executed once the view of the component is initialized</li> <li><strong>Local hook</strong>: <code>view.onRender()</code> method, executed once the component is rendered on the canvas</li> <li><strong>Global hook</strong>: <code>component:mount</code> event, called right after <code>view.onRender()</code>. The model is passed as an argument to the callback function.</li> <li><strong>Local hook</strong>: <code>model.updated()</code> method, executes when some property of the model is updated.</li> <li><strong>Global hook</strong>: <code>component:update</code> event, called after <code>model.updated()</code>. The model is passed as an argument to the callback function.
You can also listen to specific property change via <code>component:update:{propertyName}</code></li> <li><strong>Local hook</strong>: <code>model.removed()</code> method, executed when the component is removed.</li> <li><strong>Global hook</strong>: <code>component:remove</code> event, called after <code>model.removed()</code>. The model is passed as an argument to the callback function.</li></ul> <p>Below you can find an example usage of all the hooks</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>DomComponents<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'test-component'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token literal-property property">model</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">defaults</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">testprop</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Local hook: model.init'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">listenTo</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token string">'change:testprop'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handlePropChange<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Here we can listen global hooks with editor.on('...')</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function">updated</span><span class="token punctuation">(</span><span class="token parameter">property<span class="token punctuation">,</span> value<span class="token punctuation">,</span> prevValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Local hook: model.updated'</span><span class="token punctuation">,</span>
<span class="token string">'property'</span><span class="token punctuation">,</span> property<span class="token punctuation">,</span> <span class="token string">'value'</span><span class="token punctuation">,</span> value<span class="token punctuation">,</span> <span class="token string">'prevValue'</span><span class="token punctuation">,</span> prevValue<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function">removed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Local hook: model.removed'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function">handlePropChange</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'The value of testprop'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'testprop'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token literal-property property">view</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Local hook: view.init'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function">onRender</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Local hook: view.onRender'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// A block for the custom component</span>
editor<span class="token punctuation">.</span>BlockManager<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">'test-component'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Test Component'</span><span class="token punctuation">,</span>
<span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">'&lt;div data-gjs-type=&quot;test-component&quot;&gt;Test Component&lt;/div&gt;'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Global hooks</span>
editor<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">component:create</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token parameter">model</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Global hook: component:create'</span><span class="token punctuation">,</span> model<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'type'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
editor<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">component:mount</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token parameter">model</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Global hook: component:mount'</span><span class="token punctuation">,</span> model<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'type'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
editor<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">component:update:testprop</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token parameter">model</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Global hook: component:update:testprop'</span><span class="token punctuation">,</span> model<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'type'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
editor<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">component:remove</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token parameter">model</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Global hook: component:remove'</span><span class="token punctuation">,</span> model<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'type'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="components-css"><a href="#components-css" class="header-anchor">#</a> Components &amp; CSS</h2> <div class="custom-block warning"><p class="custom-block-title">WARNING</p> <p>This section is referring to GrapesJS v0.17.27 or higher</p></div> <p>If you need to add component-related styles, you can do it via <code>styles</code> property.</p> <div class="language-js extra-class"><pre class="language-js"><code>domc<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'component-css'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token literal-property property">model</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">defaults</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">attributes</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">'cmp-css'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
&lt;span&gt;Component with styles&lt;span&gt;
&lt;div class=&quot;cmp-css-a&quot;&gt;Component A&lt;/div&gt;
&lt;div class=&quot;cmp-css-b&quot;&gt;Component B&lt;/div&gt;
</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
<span class="token literal-property property">styles</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
.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 }
}
</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>This approach allows the editor to group these styles (<a href="/docs/api/css_rule.html">CssRule</a> instances) and remove them accordingly in case all references of the same component are removed.</p> <div class="custom-block danger"><p class="custom-block-title">Important caveat</p> <p></p></div> <p>In the example above we used one custom component and default sub-components. Styles are declared on our custom component only, that means if you remove all <code>.cmp-css-a</code> and <code>.cmp-css-b</code> instances from the canvas, their CssRules will still be stored in the project (<strong>here we're not talking about the CSS export, which is able to skip not used rules, but instances stored in your project JSON</strong>).</p> <p>The cleanest approach would be to follow component-oriented styling, where you declare styles only in the scope of the component itself. This is how it would look like with the example above.</p> <div class="language-js extra-class"><pre class="language-js"><code>domc<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'cmp-a'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token literal-property property">model</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">defaults</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">attributes</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">'cmp-css-a'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token string">'Component A'</span><span class="token punctuation">,</span>
<span class="token literal-property property">styles</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
.cmp-css-a { color: green }
@media (max-width: 992px) {
.cmp-css-a { color: darkgreen }
}
</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
domc<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'cmp-b'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token literal-property property">model</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">defaults</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">attributes</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">'cmp-css-b'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token string">'Component B'</span><span class="token punctuation">,</span>
<span class="token literal-property property">styles</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
.cmp-css-b { color: blue }
@media (max-width: 992px) {
.cmp-css-b { color: darkblue }
}
</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
domc<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'component-css'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token literal-property property">model</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">defaults</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">attributes</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">'cmp-css'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token string">'&lt;span&gt;Component with styles&lt;span&gt;'</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'cmp-a'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'cmp-b'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token literal-property property">styles</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
.cmp-css { color: red }
@media (max-width: 992px) {
.cmp-css{ color: darkred; }
}
</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><div class="custom-block tip"><p class="custom-block-title">Component-first styling</p> <p>By default, when you select a component in the canvas and apply styles on it, changes will be applied on its existent classes. This will result on changing of all the components with those applied classes. If you need the style to be applied only on the specific selected component you have to select componentFirst strategy in this way.</p> <div class="language-js extra-class"><pre class="language-js"><code>grapesjs<span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token operator">...</span>
<span class="token literal-property property">selectorManager</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">componentFirst</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div></div> <h3 id="external-css"><a href="#external-css" class="header-anchor">#</a> External CSS</h3> <p>If you need to load external component-specific CSS, you have to rely on the <code>script</code> property. For more details please refer to <a href="/docs/modules/Components-js.html">Components &amp; JS</a>.</p> <h2 id="components-js"><a href="#components-js" class="header-anchor">#</a> Components &amp; JS</h2> <p>If you want to know how to create Components with javascript attached (eg. counters, galleries, slideshows, etc.) check the dedicated page
<a href="/docs/modules/Components-js.html">Components &amp; JS</a></p> <h2 id="tips"><a href="#tips" class="header-anchor">#</a> Tips</h2> <h3 id="jsx-syntax"><a href="#jsx-syntax" class="header-anchor">#</a> JSX syntax</h3> <p>If you're importing big chunks of HTML string into the editor (eg. defined via Blocks) JSX might be a great compromise between performances and code readibility as it allows you to skip the parsing and the component recognition steps by keeping the HTML syntax.
By default, GrapesJS understands objects generated from React JSX preset, so, if you're working in the React app probably you're already using JSX and you don't need to do anything else, your environment is already configured to parse JSX in javascript files.</p> <p>So, instead of writing this:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// I'm adding a string, so the parsing and the component recognition steps will be executed</span>
editor<span class="token punctuation">.</span><span class="token function">addComponents</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;div&gt;
&lt;span data-gjs-type=&quot;custom-component&quot; data-gjs-prop=&quot;someValue&quot; title=&quot;foo&quot;&gt;
Hello!
&lt;/span&gt;
&lt;/div&gt;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>or this</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// I'm passing the Component Definition, so heavy steps will be skipped but the code is less readable</span>
editor<span class="token punctuation">.</span><span class="token function">addComponents</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">tagName</span><span class="token operator">:</span> <span class="token string">'div'</span><span class="token punctuation">,</span>
<span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>you can use this format</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span><span class="token function">addComponents</span><span class="token punctuation">(</span><span class="token operator">&lt;</span>div<span class="token operator">&gt;</span>
<span class="token operator">&lt;</span>custom<span class="token operator">-</span>component data<span class="token operator">-</span>gjs<span class="token operator">-</span>prop<span class="token operator">=</span><span class="token string">&quot;someValue&quot;</span> title<span class="token operator">=</span><span class="token string">&quot;foo&quot;</span><span class="token operator">&gt;</span>
Hello<span class="token operator">!</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>custom<span class="token operator">-</span>component<span class="token operator">&gt;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Another cool feature you will get by using JSX is the ability to pass component types as element tags <code>&lt;custom-component&gt;</code> instead of <code>data-gjs-type=&quot;custom-component&quot;</code></p> <h4 id="setup-jsx-syntax"><a href="#setup-jsx-syntax" class="header-anchor">#</a> Setup JSX syntax</h4> <p>For those who are not using React you have the following options:</p> <ul><li>GrapesJS has an option, <code>config.domComponents.processor</code>, thats allows you to easily implement other JSX presets. This scenario is useful if you work with a framework different from React but that uses JSX (eg. Vue). In that case, the result object from JSX pragma function (React uses <code>React.createElement</code>) will be different (you can log the JSX to see the result object) and you have to transform that in GrapesJS <a href="#component-definition">Component Definition</a> object. Below an example of usage</li></ul> <div class="language-js extra-class"><pre class="language-js"><code>grapesjs<span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token literal-property property">domComponents</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token function-variable function">processor</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">obj</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>obj<span class="token punctuation">.</span>$$<span class="token keyword">typeof</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// eg. this is a React Element</span>
<span class="token keyword">const</span> compDef <span class="token operator">=</span> <span class="token punctuation">{</span>
<span class="token literal-property property">type</span><span class="token operator">:</span> obj<span class="token punctuation">.</span>type<span class="token punctuation">,</span>
<span class="token literal-property property">components</span><span class="token operator">:</span> obj<span class="token punctuation">.</span>props<span class="token punctuation">.</span>children<span class="token punctuation">,</span>
<span class="token operator">...</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token operator">...</span>
<span class="token keyword">return</span> compDef<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><ul><li>In case you need to support JSX from scratch (you don't use a framework which supports JSX) you have, at first, implement the parser which transforms JSX in your files in something JS-readable.</li></ul> <p>For Babel users, it's just a matter of adding few plugins: <code>@babel/plugin-syntax-jsx</code> and <code>@babel-plugin-transform-react</code>. Then update your <code>.babelrc</code> file</p> <div class="language-json extra-class"><pre class="language-json"><code><span class="token punctuation">{</span>
“plugins”<span class="token operator">:</span> <span class="token punctuation">[</span>
“@babel/plugin-syntax-jsx”<span class="token punctuation">,</span>
“@babel/plugin-transform-react-jsx”
<span class="token punctuation">]</span>
<span class="token punctuation">}</span>
</code></pre></div><p>You can also customize the pragma function which executes the transformation <code>[“@babel/plugin-transform-react-jsx”, { “pragma”: “customCreateEl” }]</code>, by default <code>React.createElement</code> is used (you'll need a React instance available in the file to make it work).</p> <p>A complete example of this approach can be found <a href="https://codesandbox.io/s/x07xf" target="_blank" rel="noopener noreferrer">here<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></div> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/artf/grapesjs/edit/dev/docs/modules/Components.md" target="_blank" rel="noopener noreferrer">Edit this page on GitHub</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div> <div class="last-updated"><span class="prefix">Last Updated:</span> <span class="time">11/1/2023, 11:31:52 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
<a href="/docs/getting-started.html" class="prev">
Getting Started
</a></span> <span class="next"><a href="/docs/modules/Components-js.html">
Components &amp; JS
</a>
</span></p></div> </main></div><div class="global-ui"></div></div>
<script src="/docs/assets/js/app.7cba500a.js" defer></script><script src="/docs/assets/js/4.0070552e.js" defer></script><script src="/docs/assets/js/2.6fefd022.js" defer></script><script src="/docs/assets/js/1.d23e9fed.js" defer></script><script src="/docs/assets/js/85.c70a27f1.js" defer></script>
</body>
</html>