
Optimizely CMS 13 ES6 Editor Descriptors
- Mark Hall
- Optimizely
- April 12, 2026
Introduction
With the release if Optimizely PaaS CMS 13, there is a new way to create UI editor descriptors to allow to custom UI with managing a property. These have been one of the reasons partners can make the jobs of editors much easier by proving a custom experience when entering content. In the previous versions all the descriptors had to involve dojo. Optimizely provided a way to use react or other tools but you needed to create a dojo wrapper around the component. This post will provide and example vite.config.ts file and command to package your editor descriptors.
Server Side
You will need to make a couple of changes to your existing editors when using the new ES6 modules.
First change if you were using dojo module paths in the registration of your editor, you will need to update since there is no Dojo being called here. An example below is from a module config where we register the path.
<dojo>
<paths>
<add name="loce" path="clientResources/widgets" />
</paths>
</dojo>
In the old way we could that path to register the editor.
[EditorDescriptorRegistration(TargetType = typeof(string), UIHint = "FormImagePreview", EditorDescriptorBehavior = EditorDescriptorBehavior.OverrideDefault)]
public class ImagePreviewEditorDescriptor() : EditorDescriptor
{
public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes)
{
base.ModifyMetadata(metadata, attributes);
ClientEditingClass = "loce/formImagePreviewWidget";
}
}
Now we will need to use the Paths.ToClientResource to get the correct path since we cannot use the dojo alias paths.
[EditorDescriptorRegistration(TargetType = typeof(string), UIHint = "FormImagePreview", EditorDescriptorBehavior = EditorDescriptorBehavior.OverrideDefault)]
public class ImagePreviewEditorDescriptor() : EditorDescriptor
{
public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes)
{
base.ModifyMetadata(metadata, attributes);
ClientEditingClass = Paths.ToClientResource(GetType(), "clientResources/widgets/formImagePreviewWidget.js");
}
}
Client Side
I will not go into creating and editor because Grzegorz does that well in his post. He does not have an example on how to bundle this using vite so I will show an example vite.config.ts file.
import { resolve } from 'path';
import { defineConfig, loadEnv, ConfigEnv } from 'vite';
import react from '@vitejs/plugin-react';
/** @type {import('vite').UserConfig} */
export default ({ mode }: ConfigEnv) => {
const env = loadEnv(mode, process.cwd(), '');
return defineConfig({
plugins: [react({})],
build: {
outDir: resolve(process.cwd(), '../src/lunchin.Optimizely.Cloud.Extensions/clientResources/widgets'),
emptyOutDir: false,
sourcemap: env.MODE === 'development',
cssMinify: !(env.MODE === 'development'),
cssCodeSplit: false, // Keep all CSS in one file for global styles
minify: !(env.MODE === 'development'),
lib: {
entry: {
imagePreview: resolve(process.cwd(), 'src/editors/imagePreview/index.ts'),
//add your other widgets here
},
formats: ['es'],
},
rolldownOptions: {
output: {
entryFileNames: () => '[name].js'
}
},
},
define: {
'process.env.NODE_ENV': JSON.stringify(env.MODE)
}
});
}
This example creates one editor and puts in the correct folder for when I create the zip module. You can add mutiple editors here and it will split any dependencies into a seperate files so can be reused in all editors.
Here is the sample node commands to package the editor
"build:editors": "vite build --config vite/vite.editor-descriptors.config.ts --mode production",
"build:editors:dev": "vite build --config vite/vite.editor-descriptors.config.ts --mode development",
Share :
I am senior solution architect working at Perficient helping brands create exceptional digital experiences for their customers. I am a full stack developer who enjoys the full software development lifecycle. I have expertise in Optimizely, the Azure cloud stack, React, NextJS, CI/CD pipelines, test driven development and solution architecture.


