Anders Hattestad
Feb 20, 2015
(7 votes)

Extending the HyperLink with custom field

I needed to extend the popup with a new field where the editors could add a phone number. In EPiServer 7.5 this can be done by extending the EditorDescriptorRegistration
    [EditorDescriptorRegistration(TargetType = typeof (string), UIHint = "HyperLink",
        EditorDescriptorBehavior = EditorDescriptorBehavior.OverrideDefault)]
    public class LinkEditorDescriptor : EditorDescriptor
        private readonly LocalizationService _localizationService;

        public LinkEditorDescriptor() : this(LocalizationService.Current)

        public LinkEditorDescriptor(LocalizationService localizationService)
            _localizationService = localizationService;

        public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes)
            base.ModifyMetadata(metadata, attributes);
            IEnumerable<IContentRepositoryDescriptor> allInstances =
            List<HyperLinkModel> list = (
                from r in allInstances
                orderby r.SortOrder
                where r.LinkableTypes != null && r.LinkableTypes.Count() > 0
                select new HyperLinkModel
                    Name = r.CustomSelectTitle ?? r.Name,
                    Roots = r.Roots,
                    WidgetType = "epi-cms/widget/ContentSelector",
                    LinkableTypes = r.LinkableTypes,
                    SearchArea = r.SearchArea
            list.InsertRange(list.Count, new[]
                new HyperLinkModel
                    Name = "Email",
                    Title = _localizationService.GetString("/episerver/cms/widget/editlink/emailtooltip"),
                    DisplayName = _localizationService.GetString("/episerver/cms/widget/editlink/email"),
                    WidgetType = "epi-cms/form/EmailValidationTextBox"
                new HyperLinkModel
                    Name = "ExternalLink",
                    Title = _localizationService.GetString("/episerver/cms/widget/editlink/externallinktooltip"),
                    DisplayName = _localizationService.GetString("/episerver/cms/widget/editlink/externallink"),
                    WidgetType = "epi-cms/form/UrlValidationTextBox"
                new HyperLinkModel
                    Name = "FreeTextLink",
                    Title = "Other links",
                    DisplayName = "Other",
                    WidgetType = "alloy/TextBoxMustHaveValue"
                new HyperLinkModel
                    Name = "Anchor",
                    Title = _localizationService.GetString("/episerver/cms/widget/editlink/anchortooltip"),
                    DisplayName = _localizationService.GetString("/episerver/cms/widget/editlink/anchor"),
                    WidgetType = "epi-cms/form/AnchorSelectionEditor",
                    Invisible = true
            metadata.EditorConfiguration["providers"] = list;
            metadata.GroupName = "Href";
            metadata.GroupSettings = new GroupSettings
                Name = metadata.GroupName,
                ClientLayoutClass = "",
                DisplayUI = true
            metadata.ClientEditingClass = "epi-cms/widget/HyperLinkSelector";

    internal class HyperLinkModel
        public string Name { get; set; }
        public string DisplayName { get; set; }
        public string Title { get; set; }
        public IEnumerable<ContentReference> Roots { get; set; }
        public string WidgetType { get; set; }
        public IEnumerable<Type> LinkableTypes { get; set; }
        public bool Invisible { get; set; }
        public string SearchArea { get; set; }

I needed to create my own HyperLinkModel since its internal

Then I needed to create a dojo class like this

define("alloy/TextBoxMustHaveValue", [
    // Resources
], function (
// Resources
    ) {

    return declare([ValidationTextBox], {
        // summary:
        //    Represents the email input textbox.
        // tags:
        //    internal

        validator: function (value, constraints) {
            // summary:
            //                               Validate the text input with email address validation.
            // tags:
            //                               overrided

            return (!this.required && this._isEmpty(value)) || (!this._isEmpty(value));

        invalidMessage: resources.invalidmessage


And then register the path in modules.config

    <!-- Add a mapping from alloy to ~/ClientResources/Scripts to the dojo loader configuration -->
      <add name="alloy" path="Scripts" />


And then the result

Feb 20, 2015


Feb 23, 2015 04:40 PM

Nice! I really have to look into all this dojo stuff.

Søren Raarup
Søren Raarup Apr 7, 2015 01:21 PM

Thanks for sharing, Anders :-)

Apr 26, 2017 01:50 PM

Hi. Thank you for a great post. It have bee very helpful in several cases. 

Unfortunatly, the email link-fuction is not woking preoperly after upgrading to Episerver 10.7 when including a similar EditorDescriptorRegistration extension as above. In particular the "malto:"-prefix is no longer added. So for instance, an email link looks like the following.

Email link

So an editor needs to add the "emailto:"-prefix manually i HTML view.

Has anyone else experienced this behavior?

I have been troulbeshooting this and testing several scenarios. Removing the EditorDescriptorRegistration extension will make everything work as it supposed to. But it seems that the path to the email link widget file has been changed. So the following path is not correct and the js-files are not uploaded in the browser as they did before. 

WidgetType = "epi-cms/form/EmailValidationTextBox"

So the question is what is the new correct path? Any ideas? 

Thank you

David Tellander
David Tellander Jul 19, 2017 03:33 PM

I ran into the same problem as Ayman when using this solution, in my case on a 9.7 site.

To fix this I had to add a new property to the HyperLinkModel class:

public Dictionary WidgetSettings { get; set; }

And then on the HyperLinkModel for Email set the addMailTo setting to true, since this is false by default:

WidgetSettings = new Dictionary { {"addMailTo", true} }


Kenia Gonzalez
Kenia Gonzalez Jan 11, 2019 02:54 PM

We're using this solution in our project and it has been working fine in version 7.7 After upgrading to CMS 11.6 the link selection dialog is shown blank. The console shows the following errors:

1: ComponentController::loadComponents widgets.js:2:509770
2: FormContainer::_setupUI undefined widgets.js:2:509770

3: FormContainer::_setupUI undefined

Any ideas? Have you tested the solution in the newest version Anders?

Angel Velazquez
Angel Velazquez Nov 1, 2019 04:42 PM

Hi. We are trying to use this same solution in our project too, but we are having the same or similar results as Kenia mentioned, our dialog box is shown in blank as well.

Kenia, Did you find a way to solved this? or is there any other (if exist...) kind of development to achieve this?


James Wilkinson
James Wilkinson Nov 6, 2019 05:17 PM

Did anyone crack this? 

Ynze Feb 21, 2022 04:04 AM

For an updated version of the code that works for CMS 11, see this post:

Please login to comment.
Latest blogs
The 1001st Piece in your 1000 Piece Puzzle: .NET Default Interface Functions

I was recently working with a client who wanted a reasonably large subsystem added to Optimizely that would add automated management to their...

Greg J | Nov 28, 2022 | Syndicated blog

Video Demonstration, creating a CMS12 Alloy Sample Site

Hey All Below you will find a quick video demonstration on how to install a local version of Alloy Sample based on CMS12 / .Net 6. As you will see ...

Minesh Shah (Netcel) | Nov 28, 2022

How to create an admin user I Optimizely CMS – with Episerver CLI

In this blog post I’ll show how to create an admin user for Optimizely CMS in a new environment where you don’t have access to the admin interface.

Ove Lartelius | Nov 28, 2022 | Syndicated blog

Optimizely shortcuts in CMS 12 will get a trailing slash appended!

Not all URLs will work when the trailing slash is added, and that could cause problems. Hopefully it will be fixed soon.

Tomas Hensrud Gulla | Nov 26, 2022 | Syndicated blog

One week left of the beta certification period

Today it's one week until the last beta certification day. Do you exam no later than Wednesday the 30th.  Here are the reference and exam guides:...

Karen McDougall | Nov 23, 2022

Unbelievable FREE Heatmapping With Optimizely Web

Within this guide, you will learn how to integrate a free heat mapping tool to Optimizely Web so you can turbocharge your A/B testing capabilities....

Jon Jones | Nov 22, 2022 | Syndicated blog