Simple Custom Tool
In this example, we will create a simple custom tool to extend functionality of the editor. You can learn more about this in our documentation.
This page contains 4 examples:
- Basic Custom Tool
- Custom Tool using Built-In Property Editor
- Custom Tool using Custom Property Editor
- Custom Tool using Custom Property Editor and Mobile Override
Basic Custom Tool
Each custom tool is built in its own custom.js file which is then passed to unlayer.init
. We'll start with creating our custom.js file.
custom.js
unlayer.registerTool({
name: 'my_tool',
label: 'My Tool',
icon: 'fa-smile',
supportedDisplayModes: ['web', 'email'],
options: {},
values: {},
renderer: {
Viewer: unlayer.createViewer({
render(values) {
return '<div>I am a custom tool.</div>';
},
}),
exporters: {
web: function (values) {
return '<div>I am a custom tool.</div>';
},
email: function (values) {
return '<div>I am a custom tool.</div>';
},
},
head: {
css: function (values) {},
js: function (values) {},
},
},
});
Then, we'll pass the custom.js URL to the editor in init option customJS
.
- The URL must be absolute
- You can load multiple URLs by passing more in the array
- If you don't have the option to pass a URL, you can directly pass your JavaScript code as a string
unlayer.init({
id: 'editor-container',
displayMode: 'email',
customJS: [
'https://examples.unlayer.com/examples/simple-custom-tool/custom.js',
],
});
Preview
Here's a live running preview of our custom tool. Drag and drop the custom tool with a smiley face :)
Custom Tool with Built-In Property Editor
Let's update our custom tool to use a built-in property editor now. In this example, we will create a color picker.
To use the built-in color picker, we will update our tool to add a new property called textColor in registerTool code, and use the color_picker property editor.
You can see the full list of available built-in property editors.
unlayer.registerTool({
name: 'my_tool',
label: 'My Tool',
icon: 'fa-smile',
supportedDisplayModes: ['web', 'email'],
- options: {},
+ options: {
+ default: {
+ title: null,
+ },
+ text: {
+ title: 'Color',
+ position: 1,
+ options: {
+ textColor: {
+ label: 'Color',
+ defaultValue: '#ff0000',
+ widget: 'color_picker', // built_in property editor
+ },
+ },
+ },
+ },
values: {},
renderer: {
Viewer: unlayer.createViewer({
render(values) {
- return '<div>I am a custom tool.</div>';
+ return `<div style="color: ${values.textColor};">I am a custom tool.</div>`;
},
}),
exporters: {
web: function (values) {
- return '<div>I am a custom tool.</div>';
+ return `<div style="color: ${values.textColor};">I am a custom tool.</div>`;
},
email: function (values) {
- return '<div>I am a custom tool.</div>';
+ return `<div style="color: ${values.textColor};">I am a custom tool.</div>`;
},
},
head: {
css: function (values) {},
js: function (values) {},
},
},
});
Then, we'll pass the updated custom.js URL to the editor in init option customJS
.
unlayer.init({
id: 'editor-container',
displayMode: 'email',
customJS: [
'https://examples.unlayer.com/examples/simple-custom-tool-with-builtin-editors/custom.js',
],
});
Preview
Here's a live running preview of our custom tool with built-in editor. Drag and drop the custom tool with a smiley face, and then select it on the canvas to play with the color picker.
Custom Tool with Custom Property Editor
Let's update our custom tool to use a custom property editor now. In this example, we will create a custom color picker.
Register Property Editor
Let's register a custom property editor first. We will add this code in our custom.js file.
unlayer.registerPropertyEditor({
name: 'my_color_picker',
layout: 'bottom',
Widget: unlayer.createWidget({
render(value, updateValue, data) {
return `
<input class="value" type="text" value="${value}" />
<button class="red">Red</button>
<button class="green">Green</button>
<button class="blue">Blue</button>
`;
},
mount(node, value, updateValue, data) {
var input = node.querySelector('.value');
var redBtn = node.querySelector('.red');
var greenBtn = node.querySelector('.green');
var blueBtn = node.querySelector('.blue');
input.onchange = function (e) {
updateValue(e.target.value);
};
redBtn.onclick = function () {
updateValue('#FF0000');
};
greenBtn.onclick = function () {
updateValue('#00ff00');
};
blueBtn.onclick = function () {
updateValue('#0000ff');
};
},
}),
});
Using Custom Property Editor
Now we will update our registerTool code to use the my_color_picker
property editor we registered above.
unlayer.registerTool({
name: 'my_tool',
label: 'My Tool',
icon: 'fa-smile',
supportedDisplayModes: ['web', 'email'],
options: {
default: {
title: null,
},
text: {
title: 'Color',
position: 1,
options: {
textColor: {
label: 'Color',
defaultValue: '#ff0000',
- widget: 'color_picker', // built_in property editor
+ widget: 'my_color_picker', // custom property editor
},
},
},
},
values: {},
renderer: {
Viewer: unlayer.createViewer({
render(values) {
return `<div style="color: ${values.textColor};">I am a custom tool.</div>`;
},
}),
exporters: {
web: function (values) {
return `<div style="color: ${values.textColor};">I am a custom tool.</div>`;
},
email: function (values) {
return `<div style="color: ${values.textColor};">I am a custom tool.</div>`;
},
},
head: {
css: function (values) {},
js: function (values) {},
},
},
});
Then, we'll pass the updated custom.js URL to the editor in init option customJS
.
unlayer.init({
id: 'editor-container',
displayMode: 'email',
customJS: [
'https://examples.unlayer.com/examples/simple-custom-tool-with-property-editor/custom.js',
],
});
Preview
Here's a live running preview of our custom tool with custom property editor. Drag and drop the custom tool with a smiley face, and then select it on the canvas to play with our custom color picker.
Custom Tool with Custom Property Editor and Mobile Override
Let's add mobile overriding support to our custom tool and custom property editor.
[Step 1/3] Enable mobile override in the tool option
unlayer.registerTool({
name: 'my_tool',
label: 'My Tool',
icon: 'fa-smile',
supportedDisplayModes: ['web', 'email'],
options: {
default: {
title: null,
},
text: {
title: 'Color',
position: 1,
options: {
textColor: {
label: 'Color',
defaultValue: '#ff0000',
widget: 'my_color_picker', // custom property editor
+ overrideAllowed: true,
},
},
},
},
values: {},
renderer: {
Viewer: unlayer.createViewer({
render(values) {
return `<div style="color: ${values.textColor};">I am a custom tool.</div>`;
},
}),
exporters: {
web: function (values) {
return `<div style="color: ${values.textColor};">I am a custom tool.</div>`;
},
email: function (values) {
return `<div style="color: ${values.textColor};">I am a custom tool.</div>`;
},
},
head: {
css: function (values) {},
js: function (values) {},
},
},
});
[Step 2/3] Enable mobile override in the property editor
Let's update our custom Color Picker Property Editor to add a deviceStyles
method. This method returns a style object that will be applied to mobile devices using the @media
query (responsive design).
unlayer.registerPropertyEditor({
name: 'my_color_picker',
layout: 'bottom',
+ deviceStyles(value, _info) {
+ return {
+ color: value,
+ }
+ },
Widget: unlayer.createWidget({
render(value, updateValue, data) {
return `
<input class="value" type="text" value="${value}" />
<button class="red">Red</button>
<button class="green">Green</button>
<button class="blue">Blue</button>
`;
},
mount(node, value, updateValue, data) {
var input = node.querySelector('.value');
var redBtn = node.querySelector('.red');
var greenBtn = node.querySelector('.green');
var blueBtn = node.querySelector('.blue');
input.onchange = function (e) {
updateValue(e.target.value);
};
redBtn.onclick = function () {
updateValue('#FF0000');
};
greenBtn.onclick = function () {
updateValue('#00ff00');
};
blueBtn.onclick = function () {
updateValue('#0000ff');
};
},
}),
});
[Step 3/3] Enable mobile override in the tool renderer
To finish, let's add the auto-generated class to our exporters.
The class name follows this pattern: v-${optionName}-${cssProperty}
. In case optionName
and cssProperty
are the same, use just v-${cssProperty}
.
In our example, optionName
is textColor
which becomes text-color
(kebab case), and the cssProperty
we used was color
. Following the pattern, it becomes v-text-color-color
.
In case you need to debug what v-class-name was generated, you can run
unlayer.exportHtml(console.log, { cleanup: false })
and see the full generated html.
unlayer.registerTool({
name: 'my_tool',
label: 'My Tool',
icon: 'fa-smile',
supportedDisplayModes: ['web', 'email'],
options: {
default: {
title: null,
},
text: {
title: 'Color',
position: 1,
options: {
textColor: {
label: 'Color',
defaultValue: '#ff0000',
widget: 'my_color_picker', // custom property editor
overrideAllowed: true, // enable mobile override. step 1 of 3
},
},
},
},
values: {},
renderer: {
Viewer: unlayer.createViewer({
render(values) {
return `<div style="color: ${values.textColor};">I am a custom tool.</div>`;
},
}),
exporters: {
web: function (values) {
- return `<div style="color: ${values.textColor};">I am a custom tool.</div>`;
+ return `<div class="v-text-color-color" style="color: ${values.textColor};">I am a custom tool.</div>`;
},
email: function (values) {
- return `<div style="color: ${values.textColor};">I am a custom tool.</div>`;
+ return `<div class="v-text-color-color" style="color: ${values.textColor};">I am a custom tool.</div>`;
},
},
head: {
css: function (values) {},
js: function (values) {},
},
},
});
Then, we'll pass the updated custom.js URL to the editor in init option customJS
.
unlayer.init({
id: 'editor-container',
displayMode: 'email',
customJS: [
'https://examples.unlayer.com/examples/simple-custom-tool-with-property-editor-and-mobile-override/custom.js',
],
});
Preview
Here's a live running preview of our custom tool with custom property editor. Drag and drop the custom tool with a smiley face, and then select it on the canvas to play with our custom color picker.
Then, press the Mobile button inside the editor, and edit the color at the right panel. Now Desktop and Mobile have different colors, depending on the mobile device width.