What are Icons?
Icons are graphical representations of different elements on a website. They make the webpages visually appealing and like any other image, have a stronger connection and retention to the end user’s memory than plain text. When used in moderation and the right way, they can be self-explanatory and reduce the need for text content in a lot of use cases.
What is an Icon Library?
Icon Library is basically a curated list/dictionary of icons that ties an icon to a meaningful name. This library can then be used to pick icons for the different elements of the website. A good use case would be websites that use icons heavily, either just as a visual piece with texts like on-site navigation for Home or Search :
or visual representation of repetitive elements on the site like Phone number, address pin, person icon and more :
What is an Icon Library for Optimizely CMS?
For a recent client who was redesigning their website using Optimizely CMS, we realized that they did fit our use case above, as they had quite a lot of icons in their new designs, fitting both criteria above. And usually, icons are part of front-end styles and setup, where they are either added within HTML code, or icon SVG files are embedded within style classes in CSS files.
This was a case where they wanted CMS editors to be able to pick icons when creating content in CMS, and also maintain consistency and match designs at the same time. So, it wasn’t like CMS editors could go in and upload just about any SVG icon image and use it. This had to be controlled and configured based on designs.
So we came up with the idea of creating an Icon Library within Optimizely CMS for them, so that editors don’t actually upload and add individual icon images as assets to components directly, but instead select an icon from a pre-curated list.
How to Create an Icon Library within Optimizely CMS?
We created a Settings type with a Property List for Icon Library :
[SettingsContentType(
DisplayName = “Icon Library Settings”,
GUID = “ecb03080-472e-4e72-9ceb-c56e775b84d6”,
Description = “Icon Library Settings”,
SettingsName = “Icon Library Settings”,
AvailableInEditMode = true)]
[ImageUrl(“~/icons/cms/pages/cms-icon-page-layout-settings.png”)]
public class IconLibrarySettings : SettingsBase
{
[Display(Name = “Icons”)]
[EditorDescriptor(EditorDescriptorType = typeof(EnhancedCollectionEditorDescriptor<IconLibrary>))]
public virtual IList<IconLibrary> Icons { get; set; }
}
The IconLibrary class is basically the model behind the property list and had a string IconName property and a ContentReference IconMedia property to hold the icon asset.
public class IconLibrary
{
[Display(Name = “Icon Name”)]
public virtual string IconName { get; set; }
[Display(Name = “Icon File”)]
[UIHint(UIHint.Image)]
public virtual ContentReference IconMedia { get; set; }
}
Also, for the editor descriptor for this property list, we used EnhancedCollectionEditorDescriptor, which is part of a separate nuget package called DoubleJay.Epi.EnhancedPropertyList.EditorDescriptors. This basically allows us to see the icon image in the property list table, rather than the id of the content saved in the ContentReference property, which is the default behavior of a CollectionEditorDescriptor.
So now when we save some icons, this is how we’ll see the list in settings :
How to Use the Icon Library in Optimizely CMS?
Now that we’ve successfully created an Icon Library in Optimizely CMS, let’s talk about how to use it where we need it. Basically, we created a block type called Icon List which has one property – a single select list populated from the data saved under Icon Library settings above.
public class IconListBlock : BlockData
{
[EditorDescriptor(EditorDescriptorType = typeof(IconLibraryEditorDescriptor))]
[UIHint(“IconLibraryEditor”)]
public virtual string Icon { get; set; }
}
Here’s the selection factory code that populates the Icon List :
public class IconLibrarySelectionFactory : ISelectionFactory
{
public IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata)
{
var settingsService = ServiceLocator.Current.GetInstance<ISettingsService>();
var urlResolver = ServiceLocator.Current.GetInstance<IUrlResolver>();
var iconSettings = settingsService.GetSiteSettings<IconLibrarySettings>();
var settings = new List<ISelectItem>();
if (iconSettings?.Icons != null)
settings.AddRange(iconSettings.Icons.Select(i => new SelectItem { Text = $”{i.IconName}”, Value = urlResolver.GetUrl(i.IconMedia) }));
return settings;
}
}
Usually, our select lists in CMS are just plain text and value lists, meaning a dropdown with text values. In this case, we wanted the editor experience to be a bit more visual. Which means we wanted the editors to be able to see a small thumbnail of the actual icon image in the dropdown next to the icon name we gave in the library.
This called for the creation of a new editor descriptor that would display both the icon thumbnail and its name side by side in the icon list dropdown.
[EditorDescriptorRegistration(TargetType = typeof(string), UIHint = “IconLibraryEditor”)]
public class IconLibraryEditorDescriptor : EditorDescriptor
{
public override void ModifyMetadata(EPiServer.Shell.ObjectEditing.ExtendedMetadata metadata, IEnumerable<Attribute> attributes)
{
SelectionFactoryType = typeof(IconLibrarySelectionFactory);
ClientEditingClass = “custom-scripts/editors/iconlibraryeditor”;
base.ModifyMetadata(metadata, attributes);
}
}
And here’s our actual dojo editor logic for iconlibraryeditor.js
define([
“dojo/_base/declare”,
“dojo/_base/array”,
“dojox/html/entities”,
“epi-cms/contentediting/editors/SelectionEditor”
],
function (
declare,
array,
entities,
SelectionEditor
) {
return declare(“custom-scripts/editors/iconlibraryeditor”, [SelectionEditor], {
_setSelectionsAttr: function (newSelections) {
this.set(“options”, array.map(newSelections, function (item) {
let svghtml = “<img style=’width:1.5rem;height:1.5rem’ src='” + item.value + “‘ />”;
let html = entities.decode(“<table style=’width:20rem;’><tr><td>” + svghtml + “</td><td>” + item.text + “</td></tr></table>”);
return {
label: html,
value: item.value,
selected: item.value === this.value || !item.value && !this.value
};
}, this));
}
});
});
With everything put in place, all we need to do as developers is use the IconList block in place of a ContentReference property, in content types that need an icon property. So CMS Editors won’t drag and drop icon assets but instead, select from this Icon Library list.
Example block type:
[ContentType(DisplayName = “Icon Content block”, GUID = “090f0c6b-384c-4cf2-8072-823b3297c460”,
Description = “A block that allows you to select icon with content”, AvailableInEditMode = false)]
public class IconContentBlock : BlockData
{
[Display(Name = “Text”, Description = “Text”, Order = 10)]
[CultureSpecific]
[Searchable]
public virtual string Text { get; set; }
[QuickSelect(“H1”, “H2”, “H3”)]
[Display(Name = “Text Style”, Description = “text style.”, Order = 20)]
[CultureSpecific]
public virtual string HeadingStyle { get; set; }
[Display(Name = “Select an icon”, Order = 30)]
public virtual IconListBlock Icon { get; set; }
}
Visual appearance in CMS with custom editor descriptor :
Conclusion
Icon Library is a handy feature for icon-heavy sites, especially where we want our CMS editors to control the icons that are added to content. With the right role-based access in place, we can ensure that one super admin role can control the actual creation and management of the Icon Library itself, that all the other authors (CMS editors) can then make use of. This will allow central control over the icons that are being added to the site, so they are in line with designs and themes and are consistent across usage and meaning throughout the site.
Hope you find this helpful!
Leave A Comment