Create an icon pack for TinyMCE
Overview
This guide provides comprehensive coverage of creating, building, and deploying custom icon packs, including solutions to common issues. It details two approaches:
-
The manual approach, for adding a small number of custom icons
-
Using the Icon Pack Template tool to easily generate the required output file from a folder of SVGs.
How Icons Work in TinyMCE
A TinyMCE icon pack is a JavaScript construct containing strings of SVGs. Icon packs are often kept in separate files, but can be inlined if needed. An icon pack can be used to add one or more custom icons or to replace some or all of the default TinyMCE icons.
An icon pack only requires the custom icons to be included; the default TinyMCE icons are used as a fallback for icons missing from the custom icon pack.
Registering an icon pack
Icon packs are registered with TinyMCE using the IconManager. Whether creating the icon pack manually or using the Icon Pack Template tool, the JavaScript required to setup an icon pack looks like:
tinymce.IconManager.add('custom-pack-name', {
icons: {
'bold': '<svg width="24" height="24">...</svg>',
'italic': '<svg width="24" height="24">...</svg>',
'custom-icon': '<svg width="24" height="24">...</svg>',
// ... more icons
}
});
Creating an icon pack manually
When adding only a few icons, it may be easier to manually configure the new icon pack than to use the Icon Pack Template tool. To do this:
-
Gather the SVG files for the new icons. Extract their content string, e.g.
<svg width="24" height="24">...</svg> -
Call
tinymce.IconManager.add() -
Specify the icon pack name as the first argument
-
The second argument is an object, with key
iconsand a nested object containing the new icons with their names and SVG strings as their keys and values.
The new icons can then be used by name within TinyMCE.
|
Icon Override: If custom icons have the same name as a default TinyMCE icon, they will override the default icon. |
This JavaScript can be included as a separate icon file or inlined beside the application’s tinymce.init() call. Configure TinyMCE to load the icon pack and, if necessary, where from using the icons and icons_url options.
|
Naming Icon Pack Files: When loading icon packs from a separate file, it is safest to name the file |
Example: using a custom icon pack inline
tinymce.IconManager.add('customIcons', { // icon pack name
icons: { // list icons as name-SVG pairs
'my-custom-icon': '<svg width="24" height="24">...</svg>',
}
});
tinymce.init({
selector: '#editor',
icons: 'customIcons', // tell {productname} to load the custom icon pack
toolbar: 'myCustomButton',
setup: function(editor) {
editor.ui.registry.addToolbarButton('myCustomButton', {
icon: 'my-custom-icon' // use the custom icon for a custom toolbar button
});
}
});
Using the Icon Pack Template tool
For large custom icon packs, use the Icon Pack Template tool, which can take a folder of SVGs and generate the required output file. This approach is ideal when creating icon packs with many icons or when automating the build process.
For step-by-step instructions, see: Using the Icon Pack Template tool.
Deploying an Icon Pack file
An icon pack file can be served either:
-
With TinyMCE
-
Separate from TinyMCE
|
Default Icon Pack Location: The
|
Deploy the Icon Pack with TinyMCE
On initialization, TinyMCE will try to load any icon pack specified by the icons option. The icons in the icon pack will be merged with TinyMCE’s default icons and icons in the icon pack will overwrite the default icons with the same identifier.
For custom icon packs:
tinymce.init({
selector: 'textarea',
icons: 'my_icon_pack' // TINYMCE_BASE/icons/my_icon_pack/icons.js
});
Deploy the Icon Pack and TinyMCE Separately
On initialization, TinyMCE will try to load any icon pack specified by the icons option from the location specified by icons_url. The icons in the icon pack will be merged with TinyMCE’s default icons and icons in the icon pack will overwrite the default icons with the same identifier.
|
Understanding When using
Example:
|
Usage
To use a TinyMCE icon pack from a separate location:
-
Ensure the icon pack is available at the specified URL.
-
Add the
icons_urloption totinymce.init. -
Specify the icon pack name using the
iconssetting.
For custom icon packs:
tinymce.init({
selector: 'textarea', // change this value according to your HTML
icons_url: 'dist/icons/my_icon_pack/icons.js', // Path to custom icon pack
icons: 'my_icon_pack' // Use custom icon pack
});
Common Development Scenarios
Local Development with Custom Icon Pack
When developing locally with a custom icon pack:
tinymce.init({
selector: 'textarea',
icons_url: 'dist/icons/my_icon_pack/icons.js', // Path to custom icon pack
icons: 'my_icon_pack', // Use custom icon pack
toolbar: 'myButton',
setup: (editor) => {
editor.ui.registry.addButton('myButton', {
icon: 'bold', // Uses your custom bold icon
onAction: (_) => {
editor.insertContent(' <strong>Custom icon clicked!</strong> ');
}
});
}
});
Interactive Demo
See the custom icon pack in action with the interactive demo:
-
TinyMCE
-
HTML
-
JS
-
Edit on CodePen
Default TinyMCE Icons
Custom Icon Pack
<div style="display: flex; gap: 20px; width: 100%; flex-wrap: wrap;">
<div style="flex: 1; min-width: 300px;">
<h2>Default TinyMCE Icons</h2>
<textarea id="default-editor" style="width: 100%;">
<h2>Default Icons Editor</h2>
<p>This editor uses the <strong>default TinyMCE icons</strong>.</p>
<p>Notice the standard appearance of the toolbar buttons.</p>
<ul>
<li>Bold, italic, underline buttons</li>
<li>Link and image buttons</li>
<li>List and code buttons</li>
</ul>
</textarea>
</div>
<div style="flex: 1; min-width: 300px;">
<h2>Custom Icon Pack</h2>
<textarea id="custom-editor" style="width: 100%;">
<h2>Custom Icons Editor</h2>
<p>This editor uses a <strong>custom icon pack</strong> created with our icon pack system.</p>
<h3>How It Works:</h3>
<p><strong>Demo Setup:</strong> For this live demo, the custom icons are defined using <code>tinymce.IconManager.add()</code> directly in the JavaScript file.</p>
<p><strong>Production Setup:</strong> In normal usage, you would:</p>
<ul>
<li>Build your icon pack using the template (see our guide)</li>
<li>Place the generated <code>icons.js</code> file in <code>dist/icons/your-pack-name/</code></li>
<li>Use <code>icons_url: 'path/to/icons.js'</code> to load it</li>
</ul>
<p>The editor is configured with <code>icons: 'my-icon-pack'</code> to use the custom icons. <strong>Try the custom buttons:</strong> Look for the custom bold, italic, and audio buttons in the toolbar above.</p>
</textarea>
</div>
</div>
<div style="margin-top: 20px; padding: 15px; background: #f8f9fa; border-radius: 4px; font-size: 14px; color: #666;">
<strong>Icon Credits:</strong> Custom icons in this demo are sourced from <a href="https://freesvgicons.com/" target="_blank" rel="noopener">FreeSVGIcons.com</a> - a collection of 250k+ open-source SVG icons.
</div>
// Load custom icon pack inline (for live demo compatibility)
tinymce.IconManager.add('my-icon-pack', {
icons: {
'audio': '<svg width="24" height="24"><path d="M10.8 19q.9 0 1.5-.7t.7-1.5V13h3v-2h-4v3.9l-.6-.3-.6-.1q-1 0-1.7.7t-.6 1.6q0 .9.7 1.5t1.6.7ZM6 22q-.8 0-1.4-.6T4 20V4q0-.8.6-1.4T6 2h8l6 6v12q0 .8-.6 1.4T18 22H6Zm7-13h5l-5-5v5Z"/></svg>',
'bold': '<svg width="24" height="24"><path fill-rule="evenodd" d="M3.6 2.3a1.4 1.4 0 0 0-1.4 1.3v16.8c0 .7.7 1.4 1.4 1.4h16.8a1.4 1.4 0 0 0 1.4-1.4V3.6a1.4 1.4 0 0 0-1.4-1.3H3.6Zm6 4a1.4 1.4 0 0 0-1.3 1.3v9.3c0 .7.6 1.4 1.3 1.4H12v-.8.8a2.5 2.5 0 0 0 .2 0 4.6 4.6 0 0 0 1.6-.5c.5-.2 1-.5 1.3-1 .4-.5.7-1.2.7-2 0-.9-.3-1.6-.7-2a3.2 3.2 0 0 0-.8-.9 2.8 2.8 0 0 0 .4-.5c.4-.5.5-1.1.5-1.9s-.1-1.4-.5-1.9a3 3 0 0 0-1.1-1 3.9 3.9 0 0 0-1.6-.3H9.6Zm.1 6.5H12a3.2 3.2 0 0 1 1.2.2l.7.6c.2.2.4.6.4 1.1s-.2 1-.4 1.2a1.8 1.8 0 0 1-.7.6 3.2 3.2 0 0 1-1.1.2H9.7v-4Zm2.3 4Zm0-5.6H9.7V7.8H12l1 .2.5.5c.1.2.3.5.3 1s-.2.8-.3 1a1.4 1.4 0 0 1-.6.5 2.3 2.3 0 0 1-.9.2Z" clip-rule="evenodd"/></svg>',
'italic': '<svg width="24" height="24"><path fill-rule="evenodd" d="M3.6 2.3a1.4 1.4 0 0 0-1.4 1.3v16.8c0 .7.7 1.4 1.4 1.4h16.8a1.4 1.4 0 0 0 1.4-1.4V3.6a1.4 1.4 0 0 0-1.4-1.3H3.6ZM16 6.8h-1.5L11 17.1h1a.8.8 0 0 1 0 1.6H8a.8.8 0 0 1 0-1.6h1.5L13 6.8h-1a.8.8 0 0 1 0-1.5h4a.8.8 0 0 1 0 1.5Z" clip-rule="evenodd"/></svg>',
}
});
// Default Icons Editor
tinymce.init({
selector: '#default-editor',
icons: 'material', // use material icon pack
plugins: 'lists link image code',
toolbar: 'undo redo | bold italic underline | bullist numlist | link image code',
height: 500,
// license_key: 'gpl'
});
// Custom Icons Editor
tinymce.init({
selector: '#custom-editor',
icons: 'my-icon-pack',
plugins: 'lists link image code',
toolbar: 'undo redo | myButton1 myButton2 myButton3 | bullist numlist | link image code',
height: 500,
setup: (editor) => {
editor.ui.registry.addButton('myButton1', {
icon: 'bold', // the 'bold' icon created from 'bold.svg'
onAction: (_) => {
editor.insertContent(' <strong>It\'s my custom bold icon button!</strong> ');
}
});
editor.ui.registry.addButton('myButton2', {
icon: 'italic', // the 'italic' icon created from 'italic.svg'
onAction: (_) => {
editor.insertContent(' <strong>It\'s my custom italic icon button!</strong> ');
}
});
editor.ui.registry.addButton('myButton3', {
icon: 'audio', // the 'audio' icon created from 'audio.svg'
onAction: (_) => {
editor.insertContent(' <strong>It\'s my custom audio icon button!</strong> ');
}
});
}
});