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.
 
 
 
 

442 lines
103 KiB

<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Trait 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/94.036e5ed0.js" as="script"><link rel="preload" href="/docs/assets/js/33.a739af41.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/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/85.c70a27f1.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/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" class="sidebar-link">Components</a></li><li><a href="/docs/modules/Components-js.html" class="sidebar-link">Components &amp; JS</a></li><li><a href="/docs/modules/Traits.html" aria-current="page" class="active sidebar-link">Traits</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/docs/modules/Traits.html#add-traits-to-components" class="sidebar-link">Add Traits to Components</a></li><li class="sidebar-sub-header"><a href="/docs/modules/Traits.html#built-in-trait-types" class="sidebar-link">Built-in trait types</a></li><li class="sidebar-sub-header"><a href="/docs/modules/Traits.html#updating-traits-at-run-time" class="sidebar-link">Updating traits at run-time</a></li><li class="sidebar-sub-header"><a href="/docs/modules/Traits.html#i18n" class="sidebar-link">I18n</a></li><li class="sidebar-sub-header"><a href="/docs/modules/Traits.html#customization" class="sidebar-link">Customization</a></li><li class="sidebar-sub-header"><a href="/docs/modules/Traits.html#events" class="sidebar-link">Events</a></li></ul></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="trait-manager"><a href="#trait-manager" class="header-anchor">#</a> Trait Manager</h1> <p>In GrapesJS, Traits define different parameters and behaviors of a component. The user generally will see traits as the <em>Settings</em> of a component. A common use of traits is to customize element attributes (eg. <code>placeholder</code> for <code>&lt;input&gt;</code>) or you can also bind them to the properties of your components and react to their changes.</p> <div class="custom-block warning"><p class="custom-block-title">WARNING</p> <p>This guide is referring to GrapesJS v0.21.9 or higher.<br><br>
To get a better understanding of the content in this guide we recommend reading <a href="/docs/modules/Components.html">Components</a> first</p></div> <p></p><div class="table-of-contents"><ul><li><a href="#add-traits-to-components">Add Traits to Components</a><ul><li><a href="#categories">Categories</a></li></ul></li><li><a href="#built-in-trait-types">Built-in trait types</a><ul><li><a href="#text">Text</a></li><li><a href="#number">Number</a></li><li><a href="#checkbox">Checkbox</a></li><li><a href="#select">Select</a></li><li><a href="#color">Color</a></li><li><a href="#button">Button</a></li></ul></li><li><a href="#updating-traits-at-run-time">Updating traits at run-time</a></li><li><a href="#i18n">I18n</a></li><li><a href="#customization">Customization</a><ul><li><a href="#define-new-trait-type">Define new Trait type</a></li><li><a href="#custom-trait-manager">Custom Trait Manager</a></li></ul></li><li><a href="#events">Events</a></li></ul></div><p></p> <h2 id="add-traits-to-components"><a href="#add-traits-to-components" class="header-anchor">#</a> Add Traits to Components</h2> <p>Generally, you define traits on the definition of your new custom components (or by extending another one). Let's see in this example how to make inputs more customizable by the editor.</p> <p>All components, by default, contain two traits: <code>id</code> and <code>title</code> (at the moment of writing). So, if you select an input and open the Settings panel you will see this:</p> <img src="/docs/default-traits.png" alt="Default traits" class="img-ctr-rad" style="max-width:200px;"> <p>We can start by creating a new custom <code>input</code> component in this way:</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>Components<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'input'</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> 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 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">traits</span><span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token comment">// Strings are automatically converted to text types</span>
<span class="token string">'name'</span><span class="token punctuation">,</span> <span class="token comment">// Same as: { type: 'text', name: 'name' }</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">'select'</span><span class="token punctuation">,</span> <span class="token comment">// Type of the trait</span>
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'type'</span><span class="token punctuation">,</span> <span class="token comment">// (required) The name of the attribute/property to use on component</span>
<span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Type'</span><span class="token punctuation">,</span> <span class="token comment">// The label you will see in Settings</span>
<span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span> <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Text'</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'email'</span><span class="token punctuation">,</span> <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Email'</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'password'</span><span class="token punctuation">,</span> <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Password'</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'number'</span><span class="token punctuation">,</span> <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Number'</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">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 comment">// As by default, traits are bound to attributes, so to define</span>
<span class="token comment">// their initial value we can use attributes</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">type</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span> <span class="token literal-property property">required</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><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Now the result will be</p> <img src="/docs/input-custom-traits.png" alt="Input with custom traits" class="img-ctr-rad" style="max-width:230px;"> <p>If you want you can also define traits dynamically via functions, which will be created on component initialization. It might be useful if you need to create traits based on some other component characteristic.</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>Components<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'input'</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> 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 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 function">traits</span><span class="token punctuation">(</span><span class="token parameter">component</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token comment">// Example of some logic</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>component<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'draggable'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
result<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">'name'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
result<span class="token punctuation">.</span><span class="token function">push</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">'select'</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 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 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>If you need to react to some change of the trait you can subscribe to their attribute listeners</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>Components<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'input'</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 comment">// ...</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:attributes:type'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleTypeChange<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function">handleTypeChange</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">'Input type changed to: '</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>type<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>As already mentioned, by default, traits modify attributes of the model, but you can also bind them to the properties by using <code>changeProp</code> options.</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>Components<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'input'</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 comment">// ...</span>
<span class="token literal-property property">traits</span><span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span>
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'placeholder'</span><span class="token punctuation">,</span>
<span class="token literal-property property">changeProp</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 comment">// ...</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token comment">// As we switched from attributes to properties the</span>
<span class="token comment">// initial value should be set from the property</span>
<span class="token literal-property property">placeholder</span><span class="token operator">:</span> <span class="token string">'Initial placeholder'</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 comment">// Also the listener changes from `change:attributes:*` to `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:placeholder'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handlePlhChange<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><h3 id="categories"><a href="#categories" class="header-anchor">#</a> Categories</h3> <p>It's possible to group your traits into categories, as shown below.</p> <img src="/docs/trait-categories.png" alt="Traits with categories" class="img-ctr-rad" style="max-width:250px;"> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> category1 <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'first'</span><span class="token punctuation">,</span> <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'First category'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> category2 <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'second'</span><span class="token punctuation">,</span> <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Second category'</span><span class="token punctuation">,</span> <span class="token literal-property property">open</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
editor<span class="token punctuation">.</span>Components<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'input'</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 comment">// ...</span>
<span class="token literal-property property">traits</span><span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'trait-1'</span><span class="token punctuation">,</span> <span class="token literal-property property">category</span><span class="token operator">:</span> category1 <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'trait-2'</span><span class="token punctuation">,</span> <span class="token literal-property property">category</span><span class="token operator">:</span> category1 <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'trait-3'</span><span class="token punctuation">,</span> <span class="token literal-property property">category</span><span class="token operator">:</span> category2 <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'trait-4'</span><span class="token punctuation">,</span> <span class="token literal-property property">category</span><span class="token operator">:</span> category2 <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// Traits without categories will be rendered at the bottom</span>
<span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'trait-5'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'trait-6'</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><h2 id="built-in-trait-types"><a href="#built-in-trait-types" class="header-anchor">#</a> Built-in trait types</h2> <p>GrapesJS comes along with few built-in types that you can use to define your traits:</p> <h3 id="text"><a href="#text" class="header-anchor">#</a> Text</h3> <p>Simple text input</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">'text'</span><span class="token punctuation">,</span> <span class="token comment">// If you don't specify the type, the `text` is the default one</span>
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'my-trait'</span><span class="token punctuation">,</span> <span class="token comment">// Required and available for all traits</span>
<span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'My trait'</span><span class="token punctuation">,</span> <span class="token comment">// The label you will see near the input</span>
<span class="token comment">// label: false, // If you set label to `false`, the label column will be removed</span>
<span class="token literal-property property">placeholder</span><span class="token operator">:</span> <span class="token string">'Insert text'</span><span class="token punctuation">,</span> <span class="token comment">// Placeholder to show inside the input</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="number"><a href="#number" class="header-anchor">#</a> Number</h3> <p>Input for numbers</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">'number'</span><span class="token punctuation">,</span>
<span class="token comment">// ...</span>
<span class="token literal-property property">placeholder</span><span class="token operator">:</span> <span class="token string">'0-100'</span><span class="token punctuation">,</span>
<span class="token literal-property property">min</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token comment">// Minimum number value</span>
<span class="token literal-property property">max</span><span class="token operator">:</span> <span class="token number">100</span><span class="token punctuation">,</span> <span class="token comment">// Maximum number value</span>
<span class="token literal-property property">step</span><span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token comment">// Number of steps</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="checkbox"><a href="#checkbox" class="header-anchor">#</a> Checkbox</h3> <p>Simple checkbox input</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">'checkbox'</span><span class="token punctuation">,</span>
<span class="token comment">// ...</span>
<span class="token literal-property property">valueTrue</span><span class="token operator">:</span> <span class="token string">'YES'</span><span class="token punctuation">,</span> <span class="token comment">// Value to assign when is checked, default: `true`</span>
<span class="token literal-property property">valueFalse</span><span class="token operator">:</span> <span class="token string">'NO'</span><span class="token punctuation">,</span> <span class="token comment">// Value to assign when is unchecked, default: `false`</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="select"><a href="#select" class="header-anchor">#</a> Select</h3> <p>Select input with options</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">'select'</span><span class="token punctuation">,</span>
<span class="token comment">// ...</span>
<span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token comment">// Array of options</span>
<span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'opt1'</span><span class="token punctuation">,</span> <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Option 1'</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'opt2'</span><span class="token punctuation">,</span> <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Option 2'</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="color"><a href="#color" class="header-anchor">#</a> Color</h3> <p>Color picker</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">'color'</span><span class="token punctuation">,</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="button"><a href="#button" class="header-anchor">#</a> Button</h3> <p>Button with a command to assign</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">'button'</span><span class="token punctuation">,</span>
<span class="token comment">// ...</span>
<span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token string">'Click me'</span><span class="token punctuation">,</span>
<span class="token literal-property property">full</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// Full width button</span>
<span class="token function-variable function">command</span><span class="token operator">:</span> <span class="token parameter">editor</span> <span class="token operator">=&gt;</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'Hello'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token comment">// or you can just specify the Command ID</span>
<span class="token literal-property property">command</span><span class="token operator">:</span> <span class="token string">'some-command'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="updating-traits-at-run-time"><a href="#updating-traits-at-run-time" class="header-anchor">#</a> Updating traits at run-time</h2> <p>If you need to change some trait on your component you can update it wherever you want by using <a href="/docs/api/component.html">Component API</a></p> <p>The trait is a simple property of the component so to get the complete list of current traits you can use this:</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">// Component selected in canvas</span>
<span class="token keyword">const</span> traits <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">'traits'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
traits<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">trait</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>trait<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>
</code></pre></div><p>In case you need a single one:</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>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>component<span class="token punctuation">.</span><span class="token function">getTrait</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 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 comment">// Finds by the `name` of the trait</span>
</code></pre></div><p>If you want, for example, updating some property of the trait, do this:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// Let's update `options` of our `type` trait, defined in Input component</span>
<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>
component<span class="token punctuation">.</span><span class="token function">getTrait</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 function">set</span><span class="token punctuation">(</span><span class="token string">'options'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'opt1'</span><span class="token punctuation">,</span> <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'New option 1'</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'opt2'</span><span class="token punctuation">,</span> <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'New option 2'</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">// or with multiple values</span>
component<span class="token punctuation">.</span><span class="token function">getTrait</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 function">set</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">'My type'</span><span class="token punctuation">,</span>
<span class="token literal-property property">options</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 punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>You can also easily add new traits or remove some other by using <a href="/docs/api/component.html#addtrait"><code>addTrait</code></a>/<a href="/docs/api/component.html#removetrait"><code>removeTrait</code></a></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// Add new trait</span>
<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>
component<span class="token punctuation">.</span><span class="token function">addTrait</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'type'</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 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><span class="token punctuation">;</span>
<span class="token comment">// The `at` option indicates the index where to place the new trait,</span>
<span class="token comment">// without it, the trait will be appended at the end of the list</span>
<span class="token comment">// Remove trait</span>
component<span class="token punctuation">.</span><span class="token function">removeTrait</span><span class="token punctuation">(</span><span class="token string">'type'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="i18n"><a href="#i18n" class="header-anchor">#</a> I18n</h2> <p>To leverage the <a href="/docs/modules/I18n.html">I18n module</a>, you can refer to this schema</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token punctuation">{</span>
<span class="token literal-property property">en</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">traitManager</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">empty</span><span class="token operator">:</span> <span class="token string">'Select an element before using Trait Manager'</span><span class="token punctuation">,</span>
<span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Component settings'</span><span class="token punctuation">,</span>
<span class="token literal-property property">categories</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">categoryId</span><span class="token operator">:</span> <span class="token string">'Category label'</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 comment">// The trait `name` property is used as a key</span>
<span class="token literal-property property">labels</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">href</span><span class="token operator">:</span> <span class="token string">'Href label'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// For built-in traits, like `text` type, these are used on input DOM attributes</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">href</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">placeholder</span><span class="token operator">:</span> <span class="token string">'eg. https://google.com'</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">// For `select` types, these are used to translate option labels</span>
<span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">target</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token comment">// Here the key is the `id` of the option</span>
<span class="token literal-property property">_blank</span><span class="token operator">:</span> <span class="token string">'New window'</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 punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="customization"><a href="#customization" class="header-anchor">#</a> Customization</h2> <p>The default types should cover most of the common properties but in case you need a more advanced UI you can <a href="#define-new-trait-type">define your own types</a> or even create a completely <a href="#custom-trait-manager">custom Trait Manager UI</a> from scratch.</p> <h3 id="define-new-trait-type"><a href="#define-new-trait-type" class="header-anchor">#</a> Define new Trait type</h3> <p>For most of the cases, default types should be enough, but sometimes you might need something more.
In that case, you can define a new type of trait and bind any kind of element to it.</p> <h4 id="create-element"><a href="#create-element" class="header-anchor">#</a> Create element</h4> <p>Let's update the default <code>link</code> Component with a new kind of trait. This is the default situation of traits for a simple link.</p> <img src="/docs/default-link-comp.jpg" alt="Default link component" class="img-ctr-rad" style="max-width:210px;"> <p>Let's just replace all of its traits with a new one, <code>href-next</code>, which will allow the user to select the type of href (eg. 'url', 'email', etc.)</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// Update component</span>
editor<span class="token punctuation">.</span>Components<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'link'</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">traits</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">'href-next'</span><span class="token punctuation">,</span>
<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'href'</span><span class="token punctuation">,</span>
<span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'New href'</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>Now you'll see a simple text input because we have not yet defined our new trait type, so let's do it:</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>Traits<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'href-next'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token comment">// Expects as return a simple HTML string or an HTML element</span>
<span class="token function">createInput</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> trait <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Here we can decide to use properties from the trait</span>
<span class="token keyword">const</span> traitOpts <span class="token operator">=</span> trait<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'options'</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 keyword">const</span> options <span class="token operator">=</span> traitOpts<span class="token punctuation">.</span>length <span class="token operator">?</span> traitOpts <span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'url'</span><span class="token punctuation">,</span> <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'URL'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'email'</span><span class="token punctuation">,</span> <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Email'</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">// Create a new element container and add some content</span>
<span class="token keyword">const</span> el <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">'div'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
el<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
&lt;select class=&quot;href-next__type&quot;&gt;
</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>options<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">opt</span> <span class="token operator">=&gt;</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;option value=&quot;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>opt<span class="token punctuation">.</span>id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&quot;&gt;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>opt<span class="token punctuation">.</span>label<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/option&gt;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
&lt;/select&gt;
&lt;div class=&quot;href-next__url-inputs&quot;&gt;
&lt;input class=&quot;href-next__url&quot; placeholder=&quot;Insert URL&quot;/&gt;
&lt;/div&gt;
&lt;div class=&quot;href-next__email-inputs&quot;&gt;
&lt;input class=&quot;href-next__email&quot; placeholder=&quot;Insert email&quot;/&gt;
&lt;input class=&quot;href-next__email-subject&quot; placeholder=&quot;Insert subject&quot;/&gt;
&lt;/div&gt;
</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token comment">// Let's make our content interactive</span>
<span class="token keyword">const</span> inputsUrl <span class="token operator">=</span> el<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.href-next__url-inputs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> inputsEmail <span class="token operator">=</span> el<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.href-next__email-inputs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> inputType <span class="token operator">=</span> el<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.href-next__type'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
inputType<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'change'</span><span class="token punctuation">,</span> <span class="token parameter">ev</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">switch</span> <span class="token punctuation">(</span>ev<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> <span class="token string">'url'</span><span class="token operator">:</span>
inputsUrl<span class="token punctuation">.</span>style<span class="token punctuation">.</span>display <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
inputsEmail<span class="token punctuation">.</span>style<span class="token punctuation">.</span>display <span class="token operator">=</span> <span class="token string">'none'</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> <span class="token string">'email'</span><span class="token operator">:</span>
inputsUrl<span class="token punctuation">.</span>style<span class="token punctuation">.</span>display <span class="token operator">=</span> <span class="token string">'none'</span><span class="token punctuation">;</span>
inputsEmail<span class="token punctuation">.</span>style<span class="token punctuation">.</span>display <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
<span class="token keyword">break</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 keyword">return</span> el<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>From the example above we simply created our custom inputs (by giving also the possibility to use <code>option</code> trait property) and defined some input switch behavior on the type change. Now the result would be something like this</p> <img src="/docs/docs-init-link-trait.jpg" alt="Link with traits" class="img-ctr-rad" style="max-width:215px;"> <h4 id="update-layout"><a href="#update-layout" class="header-anchor">#</a> Update layout</h4> <p>Before going forward and making our trait work let's talk about the layout structure of a trait. You might have noticed that the trait is composed by the label and input columns, for this reason, GrapesJS allows you to customize both of them.</p> <p>For the label customization you might use <code>createLabel</code></p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>Traits<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'href-next'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token comment">// Expects as return a simple HTML string or an HTML element</span>
<span class="token function">createLabel</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> label <span class="token punctuation">}</span></span><span class="token punctuation">)</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;div&gt;
&lt;div&gt;Before&lt;/div&gt;
</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>label<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
&lt;div&gt;After&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 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><p>You've probably seen already that in trait definition you can setup <code>label: false</code> to completely remove the label column, but in case you need to force this behavior in all instances of this trait type you can use <code>noLabel</code> property</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>Traits<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'href-next'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token literal-property property">noLabel</span><span class="token operator">:</span> <span class="token boolean">true</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><p>You might also notice that by default GrapesJS applies kind of a wrapper around your inputs, generally is ok for simple inputs but probably is not what you need where you're creating a complex custom trait. To remove the default wrapper you can use the <code>templateInput</code> option</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>Traits<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'href-next'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token comment">// Completely remove the wrapper</span>
<span class="token literal-property property">templateInput</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
<span class="token comment">// Use a new one, by specifying with `data-input` attribute where to place the input container</span>
<span class="token literal-property property">templateInput</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;div class=&quot;custom-input-wrapper&quot;&gt;
Before input
&lt;div data-input&gt;&lt;/div&gt;
After input
&lt;/div&gt;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
<span class="token comment">// It might also be a function, expects an HTML string as the result</span>
<span class="token function">templateInput</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> trait <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token string">'&lt;div ...'</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><img src="/docs/docs-link-trait-raw.jpg" alt="Basic custom link trait" class="img-ctr-rad" style="max-width:215px;"> <p>In this case, the result will be quite raw and unstyled but the point of custom trait types is to allow you to reuse your own styled inputs, probably already designed and defined (or implemented in some UI framework).
For now, let's keep the default input wrapper and continue with the integration of our custom trait.</p> <h4 id="bind-to-component"><a href="#bind-to-component" class="header-anchor">#</a> Bind to component</h4> <p>At the current state, our element created in <code>createInput</code> is not binded to the component so nothing happens when you update inputs, so let's do it now</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>Traits<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'href-next'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// Update the component based on element changes</span>
<span class="token comment">// `elInput` is the result HTMLElement you get from `createInput`</span>
<span class="token function">onEvent</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> elInput<span class="token punctuation">,</span> component<span class="token punctuation">,</span> event <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> inputType <span class="token operator">=</span> elInput<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.href-next__type'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> href <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
<span class="token keyword">switch</span> <span class="token punctuation">(</span>inputType<span class="token punctuation">.</span>value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> <span class="token string">'url'</span><span class="token operator">:</span>
<span class="token keyword">const</span> valUrl <span class="token operator">=</span> elInput<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.href-next__url'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>value<span class="token punctuation">;</span>
href <span class="token operator">=</span> valUrl<span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> <span class="token string">'email'</span><span class="token operator">:</span>
<span class="token keyword">const</span> valEmail <span class="token operator">=</span> elInput<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.href-next__email'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>value<span class="token punctuation">;</span>
<span class="token keyword">const</span> valSubj <span class="token operator">=</span> elInput<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.href-next__email-subject'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>value<span class="token punctuation">;</span>
href <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">mailto:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>valEmail<span class="token interpolation-punctuation punctuation">}</span></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>valSubj <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">?subject=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>valSubj<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
component<span class="token punctuation">.</span><span class="token function">addAttributes</span><span class="token punctuation">(</span><span class="token punctuation">{</span> href <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>Now, most of the stuff should already work (you can update the trait and check the HTML in code preview). You might wonder how the editor captures the input change and how is possible to control it.
By default, the base trait wrapper applies a listener on <code>change</code> event and calls <code>onEvent</code> on any captured event (to be captured the event should be able to <a href="https://stackoverflow.com/questions/4616694/what-is-event-bubbling-and-capturing" target="_blank" rel="noopener noreferrer">bubble<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>). If you want, for example, to update the component on <code>input</code> event you can change the <code>eventCapture</code> property</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>Traits<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'href-next'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token literal-property property">eventCapture</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'input'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// you can use multiple events in the array</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>The last thing, you might have noticed the wrong initial render of our trait, where inputs are not populated in case of already defined <code>href</code> attribute. This step should be done in <code>onUpdate</code> method</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>Traits<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'href-next'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// Update elements on the component change</span>
<span class="token function">onUpdate</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> elInput<span class="token punctuation">,</span> component <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> href <span class="token operator">=</span> component<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>href <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> inputType <span class="token operator">=</span> elInput<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.href-next__type'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> type <span class="token operator">=</span> <span class="token string">'url'</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>href<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token string">'mailto:'</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> inputEmail <span class="token operator">=</span> elInput<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.href-next__email'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> inputSubject <span class="token operator">=</span> elInput<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.href-next__email-subject'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> mailTo <span class="token operator">=</span> href<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">'mailto:'</span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'?'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> email <span class="token operator">=</span> mailTo<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> params <span class="token operator">=</span> <span class="token punctuation">(</span>mailTo<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'&amp;'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">acc<span class="token punctuation">,</span> item</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> items <span class="token operator">=</span> item<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'='</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
acc<span class="token punctuation">[</span>items<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> items<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> acc<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>
type <span class="token operator">=</span> <span class="token string">'email'</span><span class="token punctuation">;</span>
inputEmail<span class="token punctuation">.</span>value <span class="token operator">=</span> email <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">;</span>
inputSubject<span class="token punctuation">.</span>value <span class="token operator">=</span> params<span class="token punctuation">.</span>subject <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
elInput<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.href-next__url'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>value <span class="token operator">=</span> href<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
inputType<span class="token punctuation">.</span>value <span class="token operator">=</span> type<span class="token punctuation">;</span>
inputType<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">CustomEvent</span><span class="token punctuation">(</span><span class="token string">'change'</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>Now the trait will update even on component change like:</p> <div class="language-js extra-class"><pre class="language-js"><code>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">addAttributes</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">href</span><span class="token operator">:</span> <span class="token string">'mailto:new-email@test.com?subject=NewSubject'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p>To recap what we have done so far, to create a custom trait type all you will need are 3 methods:</p> <ul><li><code>createInput</code> - Where we define our custom HTML element</li> <li><code>onEvent</code> - How to update the component on inputs changes</li> <li><code>onUpdate</code> - How to update inputs on component changes</li></ul> <h4 id="result"><a href="#result" class="header-anchor">#</a> Result</h4> <p>The final result of what we have done can be seen here
<iframe width="100%" height="300" src="//jsfiddle.net/artur_arseniev/yf6amdqb/10/embedded/js,html,css,result" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p> <h4 id="integrate-external-ui-components"><a href="#integrate-external-ui-components" class="header-anchor">#</a> Integrate external UI components</h4> <p>By looking at the example above might seems like a lot of code, but at the end, it's just about a little bit of logic and the native DOM API which is not super pretty. If you use a modern UI client framework (eg. Vue, React, etc.) you could see that the integration is even easier. There is how it would be integrating a custom <a href="https://github.com/NightCatSama/vue-slider-component" target="_blank" rel="noopener noreferrer">Vue Slider Component<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> as a trait</p> <div class="language-js extra-class"><pre class="language-js"><code>editor<span class="token punctuation">.</span>Traits<span class="token punctuation">.</span><span class="token function">addType</span><span class="token punctuation">(</span><span class="token string">'slider'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token function">createInput</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> trait <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> vueInst <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token function-variable function">render</span><span class="token operator">:</span> <span class="token parameter">h</span> <span class="token operator">=&gt;</span> <span class="token function">h</span><span class="token punctuation">(</span>VueSlider<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">$mount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> sliderInst <span class="token operator">=</span> vueInst<span class="token punctuation">.</span>$children<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
sliderInst<span class="token punctuation">.</span><span class="token function">$on</span><span class="token punctuation">(</span><span class="token string">'change'</span><span class="token punctuation">,</span> <span class="token parameter">ev</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">onChange</span><span class="token punctuation">(</span>ev<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Use onChange to trigger onEvent</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>sliderInst <span class="token operator">=</span> sliderInst<span class="token punctuation">;</span>
<span class="token keyword">return</span> vueInst<span class="token punctuation">.</span>$el<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function">onEvent</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> component <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> value <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>sliderInst<span class="token punctuation">.</span><span class="token function">getValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token number">0</span><span class="token punctuation">;</span>
component<span class="token punctuation">.</span><span class="token function">addAttributes</span><span class="token punctuation">(</span><span class="token punctuation">{</span> value <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">onUpdate</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> component <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> value <span class="token operator">=</span> component<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>value <span class="token operator">||</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>sliderInst<span class="token punctuation">.</span><span class="token function">setValue</span><span class="token punctuation">(</span>value<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><iframe width="100%" height="300" src="//jsfiddle.net/artur_arseniev/x9sw2udv/embedded/js,html,css,result" allowfullscreen="allowfullscreen" frameborder="0"></iframe> <p>The integration with external components is possible by following these simple core points:</p> <ol><li><strong>Component rendering</strong>: <code>new Vue({ render: ...</code><br>
Depends on the framework, for example, in React it should be <code>ReactDOM.render(element, ...</code></li> <li><strong>Change propagation</strong>: <code>sliderInst.$on('change', ev =&gt; this.onChange(ev))</code><br>
The framework should have a mechanism to subscribe to changes and the component <a href="https://nightcatsama.github.io/vue-slider-component/#/api/events" target="_blank" rel="noopener noreferrer">should expose that change<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><br>
We've also used <code>onChange</code> method which comes handy when you need to trigger manually the <code>onEvent</code> event (you should never call directly <code>onEvent</code> method, but only via <code>onChange</code> when you need)</li> <li><strong>Property getters/setters</strong>: <a href="https://nightcatsama.github.io/vue-slider-component/#/api/methods?hash=getvalue" target="_blank" rel="noopener noreferrer"><code>sliderInst.getValue()</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 href="https://nightcatsama.github.io/vue-slider-component/#/api/methods?hash=setvaluevalue" target="_blank" rel="noopener noreferrer"><code>sliderInst.setValue(value)</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><br>
The component should allow to read and write data from the instance</li></ol> <h3 id="custom-trait-manager"><a href="#custom-trait-manager" class="header-anchor">#</a> Custom Trait Manager</h3> <p>The default Trait Manager UI should handle most of the common tasks but in case you need more advanced logic/elements, you can create your custom one from scratch.</p> <p>All you have to do is to indicate to the editor your intent to use a custom UI and then subscribe to the <code>trait:custom</code> event that will trigger on any necessary update of the UI.</p> <div class="language-js extra-class"><pre class="language-js"><code><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 comment">// ...</span>
<span class="token literal-property property">traitManager</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">custom</span><span class="token operator">:</span> <span class="token boolean">true</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 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 string">'trait:custom'</span><span class="token punctuation">,</span> <span class="token parameter">props</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token comment">// props.container (HTMLElement) - The default element where you can append your custom UI</span>
<span class="token comment">// Here you would put the logic to render/update your UI.</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>In the example below we'll replicate most of the default functionality by using the <a href="/docs/api/trait_manager.html">Traits API</a>.</p> <iframe width="100%" height="500" src="//jsfiddle.net/artur_arseniev/hszpw2rb/embedded/js,html,css,result/dark/?menuColor=fff&amp;fontColor=333&amp;accentColor=e67891" allowfullscreen="allowfullscreen" frameborder="0"></iframe> <h2 id="events"><a href="#events" class="header-anchor">#</a> Events</h2> <p>For a complete list of available events, you can check it <a href="/docs/api/trait_manager.html#available-events">here</a>.</p></div> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/artf/grapesjs/edit/dev/docs/modules/Traits.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">2/20/2024, 1:10:36 AM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
<a href="/docs/modules/Components-js.html" class="prev">
Components &amp; JS
</a></span> <span class="next"><a href="/docs/modules/Blocks.html">
Blocks
</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/94.036e5ed0.js" defer></script><script src="/docs/assets/js/33.a739af41.js" defer></script>
</body>
</html>