Try our conversational search powered by Generative AI!

Configure TinyMCE Editor Toolbar through code


Hi, I see from that through soft config in the CMS user interface it is possible to customise the toolbar for XHTMLString properties.

Is it possible to have this level of control in the C# code of my website? I.e. in some app startup code or even better declaratively through attributes on a defined page or block content type?


Aug 19, 2014 15:34

Unfortunately there is no attribute you could use in your models to decorate Xhtml properties with. However youcould probably create one on your own. It's actually quite simple to create settings from code and add them to properties. I will probably write a blog post about it soon and make it as an attribute. In the meanwhile you could use following code, e.g. in an initializable module.

First create the setting:

var defaultSettings = new TinyMCESettings()
    Width = 580,
    Height = 300,
    ToolbarRows = new List()
        new ToolbarRow(new []
        new ToolbarRow(new []

Then you need to save it, in this case we will save it as a global setting and not just on a property:

var propertySettingsRepo = ServiceLocator.Current.GetInstance();

var settingsWrapper = propertySettingsRepo.GetGlobals(typeof(TinyMCESettings))
        .FirstOrDefault(s => s.DisplayName == "Default");

if (settingsWrapper == null)
    settingsWrapper = new PropertySettingsWrapper();

settingsWrapper.DisplayName = "Default";
settingsWrapper.IsDefault = true;
settingsWrapper.IsGlobal = true;
settingsWrapper.PropertySettings = defaultSsettings;


Then we need to apply it to a property, this is however not necessary in our case because the IsDefault is set to true and will apply to all Xhtml properties anyways:

var propertyNames = new[] { "MainBody", "MainIntro" };
var propertyDefinitionRepo = ServiceLocator.Current.GetInstance();
var contentTypes = ServiceLocator.Current.GetInstance().List();

foreach (var contentType in contentTypes)
    var propertyDefinitions = contentType.PropertyDefinitions.Where(pd =>
            propertyNames.Any(propertyName => propertyName.Equals(pd.Name, StringComparison.OrdinalIgnoreCase)));

    foreach (var property in propertyDefinitions.Where(definition => definition.SettingsID == Guid.Empty))
        var settingsContainer = new PropertySettingsContainer(Guid.Empty);


        var writeableClone = property.CreateWritableClone();
        writeableClone.SettingsID = settingsContainer.Id;

Hope this helps!

Aug 20, 2014 4:39

Did it work Daniel?

Aug 21, 2014 10:42

This could also be solved by only creating an EditorDescriptor that sets your programmatically created setting. No need to save it.

A blog post about this will come up this weekend.

Aug 22, 2014 9:17

Thanks Johan and Alf - we'll give this a go and let you know.

In the meantime you guys might like to see the latest EPiServer 7.5 sites's we've released:

...all on the latest 7.11 drop, using MVC 4 and extensive use of blocks, with an automated testing framework that mocks the various repositories in EPiServer to allow us to automate the functionality of our pages and blocks.

Loving EPiServer :)

Aug 22, 2014 9:29


I can mention that we have been working on adding native support for this in the platform and unless we find some blocking issues during testing, this should be added during the coming month or so.

Aug 22, 2014 11:37

That feature is long overdue Linus :) Thank you for finally adding it.

Aug 22, 2014 15:44

Hi Alf

Any news on the blog post on creating EditorDiscriptor for TinyMCE custom settings?

Sep 03, 2014 11:06

Hi, Sorry I ran into some problems about it in 7.5 comparing to my approach in 7.0/7.1

Need to gather my thoughts to EPiServer to see how the approach could for 7.5

Thanks for the reminder.

Sep 03, 2014 11:08

The code for the main product functionality is pretty much done. However, since the CMS core and UI packages has been split into separate releases and the new functionality affects both, it's currently in the process of being added to both packages. This might take a few weeks but hopefully, it will be out in September.

Sep 03, 2014 13:00

Hi Linus, Alf

Thank you both for the update. I have managed to do it using a Custom Editor Descriptor.

Edited, Sep 03, 2014 13:02

Has this been added to EPiServer now? If so, how do I do it, some kind of attribute? 

Currently i've implemented it with an EditorDescriptor but I get an 404 on epiexternaltoolbar, if I remove that plugin with code, everything works as it should. When looking in the I can see that the folder epiexternaltoolbar doesn't exists in the location epi/TinyMCE is looking, the folder is located in the CMS.ZIP/Util/Editor/tinymce/plugins/epiexternaltoolbar folder but Epi is looking in the folder(where it doesnt exists).

Heres my code(with the epiexternaltoolbar workaround), basically a modified version of this

public class EditorButtonEditorDescriptor : EditorDescriptor
    private const string Plugins = "plugins";
    private const string EpiExternalToolBar = "epiexternaltoolbar";

    public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes)
        var attributeValue = metadata.Attributes.OfType<EditorButtonsAttribute>().SingleOrDefault();
        if (attributeValue == null) return;

        var property = (PropertyData) metadata.Model;
        var content = metadata.FindOwnerContent();

        var settings = content.GetPropertySettings<TinyMCESettings>(property.Name);

        var options = new TinyMCEInitOptions(TinyMCEInitOptions.InitType.EditMode, settings, content);
        if (options.InitOptions.ContainsKey(Plugins))
            var plugins = (string)options.InitOptions[Plugins];
            options.InitOptions[Plugins] = RemoveEpiExternalToolbar(plugins);
        metadata.EditorConfiguration[Plugins] = options.InitOptions;

        base.ModifyMetadata(metadata, attributes);

    private static string RemoveEpiExternalToolbar(string plugins)
        if (plugins.Contains(EpiExternalToolBar))
            var pluginsList = plugins.Split(',').ToList();
            return string.Join(",", pluginsList);

        return plugins;
public class EditorButtonsAttribute : Attribute
    private ToolbarRow _toolbarRow = new ToolbarRow();

    public EditorButtonsAttribute(params string[] toolbarRowButtons)
        foreach (var toolbarRowButton in toolbarRowButtons)

    public ToolbarRow ToolbarRow
        get { return _toolbarRow; }
        set { _toolbarRow = value; }
public class EditorialBlock : SiteBlockData
    [Display(GroupName = SystemTabNames.Content)]
    [EditorButtons(new[] { "bold" })]
    public virtual XhtmlString MainBody { get; set; }

Edited, Apr 23, 2016 15:30

Thanks for sharing these worthy codes.

exercise classes

Aug 30, 2016 10:23

Did anyone ever manage to achieve this?

Josef-Ottosson's code isn't working for me - the TinyMCE renders with the default toolbar. The "epiexternaltoolbar" plugin wasn't being loaded for me (guessing it's a bug resolved in a later version of the CMS).

Also, this code didn't work either:

It just renders a readonly version of the TinyMCE editor, with no toolbar options (regardless of what you pass in via the attribute).

Aug 16, 2017 17:24

Yes, this should work OOTB now.

[ServiceConfiguration(ServiceType = typeof(PropertySettings))]
public class SimpleTinyMceSettings : PropertySettings<TinyMCESettings>
    public SimpleTinyMceSettings()
        this.DisplayName = "Simple settings";

    public override Guid ID
            return new Guid("326c8ae8-685d-4387-872a-006fb45818d5");

    public override TinyMCESettings GetPropertySettings()
        return new TinyMCESettings
            ContentCss = "/css/editor.css",
            Width = 580,
            Height = 300,
            //// NonVisualPlugins = new[] { "optimizededitor", "contextmenu" },
            ToolbarRows = new List<ToolbarRow>
                new ToolbarRow(new[]

And then decorate your properties like this:

public virtual XhtmlString TeaserBody { get; set; }

You can also make the setting default for all XHTML properties (those without PropertySettings attribute) by setting this.IsDefault = true; in the constructor.

Aug 16, 2017 17:29

That works, excellent.

Thanks Johan - may be worth you writing a blog post about that :-)

Aug 16, 2017 17:38

Or just read the manual ;)

Aug 16, 2017 17:40
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.