Icon AddOn
Overview
The Icon AddOn (type: icons
, plural) allows you to insert icon sets with images, text labels, and links. This is perfect for social media links, feature highlights with icons, or any visual navigation elements.
Prerequisites
Before implementing an Icon AddOn in your code, you must first create the addon in the Beefree SDK Developer Console:
Log into the Developer Console and navigate to your application
Create a new Custom AddOn and select "Icon" as the type
Configure the addon with a unique handle (e.g.,
my-icon-addon
)Choose your implementation method (Content Dialog or External iframe)
Save the addon configuration
Content Object Schema
Required Structure
The Icon AddOn uses a unique plural naming convention—note that the type is 'icons'
(plural) and the value contains an icons
array. Each icon object in the array represents a separate icon element that will be displayed together as a set. This structure allows you to create cohesive icon groups like social media links or feature lists in a single insertion.
Important: The type is 'icons'
(plural), not 'icon'
{
type: 'icons', // Note: plural 'icons'
value: {
icons: [ // Required: Array of icon objects
{
image: string, // Required: Icon image URL
text: string, // Optional: Label text
target: string, // Optional: '_self', '_blank', etc.
alt: string, // Optional: Alt text
title: string, // Optional: Title attribute
href: string, // Optional: Link URL
width: string, // Optional: e.g., '32px'
height: string, // Optional: e.g., '32px'
textPosition: string // Optional: 'top', 'bottom', 'left', 'right'
}
]
}
}
Basic Example
This simple example creates a set of three social media icons without any styling or advanced configuration. The minimal properties (image, href, alt, width, height) are sufficient for basic icon display, and users can further customize the appearance using the editor's sidebar after insertion.
resolve({
type: 'icons',
value: {
icons: [
{
image: 'https://example.com/icons/facebook.png',
href: 'https://facebook.com',
alt: 'Facebook',
width: '32px',
height: '32px'
},
{
image: 'https://example.com/icons/twitter.png',
href: 'https://twitter.com',
alt: 'Twitter',
width: '32px',
height: '32px'
},
{
image: 'https://example.com/icons/instagram.png',
href: 'https://instagram.com',
alt: 'Instagram',
width: '32px',
height: '32px'
}
]
}
});
Complete Example with Labels
This comprehensive example shows all available icon properties, including text labels positioned below each icon and proper link targeting. The textPosition: 'bottom'
places labels beneath icons, creating a polished social media bar. Using consistent sizing and proper alt text ensures accessibility and visual cohesion across all icons in the set.
resolve({
type: 'icons',
value: {
icons: [
{
image: 'https://example.com/icons/facebook.png',
text: 'Facebook',
href: 'https://facebook.com',
target: '_blank',
alt: 'Visit our Facebook page',
title: 'Facebook',
width: '32px',
height: '32px',
textPosition: 'bottom'
},
{
image: 'https://example.com/icons/twitter.png',
text: 'Twitter',
href: 'https://twitter.com',
target: '_blank',
alt: 'Follow us on Twitter',
title: 'Twitter',
width: '32px',
height: '32px',
textPosition: 'bottom'
},
{
image: 'https://example.com/icons/linkedin.png',
text: 'LinkedIn',
href: 'https://linkedin.com',
target: '_blank',
alt: 'Connect on LinkedIn',
title: 'LinkedIn',
width: '32px',
height: '32px',
textPosition: 'bottom'
}
]
}
});
Content Dialog Implementation
Basic Handler
The Content Dialog method enables programmatic icon insertion through a JavaScript handler. When users drag your icon addon onto the stage, this handler function is invoked and immediately resolves with a predefined set of icons. This pattern works perfectly for static icon sets that don't require user configuration, providing instant insertion of consistently styled icon groups.
const beeConfig = {
container: 'bee-editor',
// Enable the addon with Direct Open feature
addOns: [
{
id: 'my-icon-addon', // Must match handle from Console
openOnDrop: true
}
],
// Define the handler for icon insertion
contentDialog: {
addOn: {
handler: (resolve, reject, args) => {
// Check which addon triggered this handler
if (args.contentDialogId === 'my-icon-addon') {
// Immediately insert a set of icons
resolve({
type: 'icons',
value: {
icons: [
{
image: 'https://example.com/icons/facebook.png',
href: 'https://facebook.com',
alt: 'Facebook',
width: '32px',
height: '32px'
},
{
image: 'https://example.com/icons/twitter.png',
href: 'https://twitter.com',
alt: 'Twitter',
width: '32px',
height: '32px'
}
]
}
});
}
}
}
}
};
Pattern: Dynamic Icon Generation
This pattern demonstrates programmatic icon generation from a data structure, making it easy to maintain and update your icon sets. By defining your icon configurations in a structured object, you can map through them to generate the proper schema format. This approach is particularly useful when icon sets are managed in a configuration file or fetched from an API, allowing for centralized management of all icon properties.
contentDialog: {
addOn: {
handler: (resolve, reject, args) => {
// Define icon configurations
const socialNetworks = [
{
name: 'Facebook',
iconUrl: 'https://example.com/icons/facebook.png',
profileUrl: 'https://facebook.com'
},
{
name: 'Twitter',
iconUrl: 'https://example.com/icons/twitter.png',
profileUrl: 'https://twitter.com'
},
{
name: 'LinkedIn',
iconUrl: 'https://example.com/icons/linkedin.png',
profileUrl: 'https://linkedin.com'
}
];
// Transform data into icon schema
const icons = socialNetworks.map(network => ({
image: network.iconUrl,
text: network.name,
href: network.profileUrl,
target: '_blank',
alt: `Visit our ${network.name} page`,
width: '32px',
height: '32px',
textPosition: 'bottom'
}));
resolve({
type: 'icons',
value: { icons }
});
}
}
}
Pattern: User Selection
This advanced pattern shows how to let users customize which icons to include and their URLs before insertion. By opening a custom selection interface, users can choose from available social networks and provide their specific profile URLs. The handler waits for user confirmation, validates the selections, and then generates the icon set based on user input. This provides maximum flexibility while maintaining consistency in icon styling and structure.
contentDialog: {
addOn: {
handler: (resolve, reject, args) => {
// Open your custom UI for icon selection
// Replace 'yourIconSelector' with your actual UI component
yourIconSelector.open({
availableNetworks: ['Facebook', 'Twitter', 'Instagram', 'LinkedIn'],
onSave: (selectedNetworks) => {
// Filter out any without URLs and transform to icon schema
const icons = selectedNetworks
.filter(network => network.url)
.map(network => ({
image: network.iconUrl,
text: network.name,
href: network.url,
target: '_blank',
alt: `${network.name}`,
width: '32px',
height: '32px',
textPosition: 'bottom'
}));
// Resolve with user-configured icons
resolve({
type: 'icons',
value: { icons }
});
},
onCancel: () => {
// User canceled - reject to abort insertion
reject();
}
});
}
}
}
Iframe Implementation
Conceptual Flow
The Iframe method allows you to create a fully custom interface for icon configuration using any web technology. Your iframe application communicates with Beefree through postMessage
events, following a specific protocol. This approach is ideal when you need a rich UI for icon selection, URL configuration, or visual preview of icon arrangements before insertion into the email template.
Required postMessage Communication
Implement the standard postMessage protocol to integrate your iframe with Beefree. First, notify Beefree when your iframe is loaded and specify the dialog dimensions. Listen for the "init" message to receive editor context. When the user finishes configuring icons, send "onSave" with your icons array. If the user cancels, send "onCancel" to close the dialog without inserting content.
1. Send "loaded" when your iframe is ready:
window.parent.postMessage({
action: 'loaded',
data: {
width: '600px',
height: '500px',
isRounded: true,
hasTitleBar: true,
showTitle: true
}
}, '*');
2. Listen for "init" message from Beefree:
window.addEventListener('message', (event) => {
const { action, data } = event.data;
if (action === 'init') {
console.log('Editor locale:', data.locale);
// Initialize your icon configuration UI
}
});
3. Send "onSave" with icon data:
// When user clicks save/insert button
window.parent.postMessage({
action: 'onSave',
data: {
type: 'icons',
value: {
icons: [
{
image: 'https://example.com/icons/facebook.png',
href: 'https://facebook.com',
alt: 'Facebook',
width: '32px',
height: '32px'
}
// ... more icons
]
}
}
}, '*');
4. Send "onCancel" if user cancels:
// When user clicks cancel or closes dialog
window.parent.postMessage({
action: 'onCancel'
}, '*');
Simple Iframe Example
This complete HTML example provides a functional icon configuration interface. It demonstrates the full postMessage protocol and includes simple inputs for configuring a social media icon set. Users can enter their social profile URLs, and the interface automatically generates properly formatted icons. You can expand this basic example with icon selection, image uploads, custom styling options, or visual preview capabilities.
<!DOCTYPE html>
<html>
<head>
<title>Icon Configurator</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
}
.icon-input {
margin: 15px 0;
}
input {
width: 100%;
padding: 8px;
margin: 5px 0;
}
button {
padding: 10px 20px;
margin-right: 10px;
}
</style>
</head>
<body>
<h2>Configure Social Icons</h2>
<div class="icon-input">
<label>Facebook URL:</label>
<input type="url" id="facebookUrl" placeholder="https://facebook.com/yourpage">
</div>
<div class="icon-input">
<label>Twitter URL:</label>
<input type="url" id="twitterUrl" placeholder="https://twitter.com/yourhandle">
</div>
<div class="icon-input">
<label>Instagram URL:</label>
<input type="url" id="instagramUrl" placeholder="https://instagram.com/yourhandle">
</div>
<button onclick="insertIcons()">Insert Icons</button>
<button onclick="cancel()">Cancel</button>
<script>
// Notify Beefree that iframe is loaded and ready
window.parent.postMessage({
action: 'loaded',
data: {
width: '600px',
height: '500px',
isRounded: true,
hasTitleBar: true,
showTitle: true
}
}, '*');
function insertIcons() {
const icons = [];
// Facebook
const fbUrl = document.getElementById('facebookUrl').value;
if (fbUrl) {
icons.push({
image: 'https://example.com/icons/facebook.png',
text: 'Facebook',
href: fbUrl,
target: '_blank',
alt: 'Facebook',
width: '32px',
height: '32px',
textPosition: 'bottom'
});
}
// Twitter
const twitterUrl = document.getElementById('twitterUrl').value;
if (twitterUrl) {
icons.push({
image: 'https://example.com/icons/twitter.png',
text: 'Twitter',
href: twitterUrl,
target: '_blank',
alt: 'Twitter',
width: '32px',
height: '32px',
textPosition: 'bottom'
});
}
// Instagram
const instaUrl = document.getElementById('instagramUrl').value;
if (instaUrl) {
icons.push({
image: 'https://example.com/icons/instagram.png',
text: 'Instagram',
href: instaUrl,
target: '_blank',
alt: 'Instagram',
width: '32px',
height: '32px',
textPosition: 'bottom'
});
}
// Validate that at least one icon was provided
if (icons.length === 0) {
alert('Please enter at least one social media URL');
return;
}
// Send icons to Beefree
window.parent.postMessage({
action: 'onSave',
data: {
type: 'icons',
value: { icons }
}
}, '*');
}
function cancel() {
window.parent.postMessage({ action: 'onCancel' }, '*');
}
</script>
</body>
</html>
Text Position Options
The textPosition
property determines where the label appears relative to the icon:
'bottom'
- Text below icon (common for social media)'top'
- Text above icon'left'
- Text to left of icon'right'
- Text to right of icon
Last updated
Was this helpful?