Control which editor features are available to users using the Feature API.

The Feature API provides control over the visibility and availability of editor functionality. Use it to hide delete buttons from certain users, disable crop controls based on context, or conditionally enable features based on user roles or selection state. Unlike hiding UI elements with ordering APIs, disabling features affects both the UI and underlying functionality.
This guide covers how to enable and disable features with simple toggles, create custom predicates for conditional feature access, use glob patterns for bulk operations, and debug feature configurations.
Feature API Methods#
The following table summarizes the main Feature API methods and when to use each:
| Method | Use Case |
|---|---|
cesdk.feature.enable() | Enable features with their default predicates |
cesdk.feature.disable() | Disable features (hide from UI) |
cesdk.feature.set() | Set features with custom predicates or boolean values |
cesdk.feature.isEnabled() | Check if a feature is currently enabled |
cesdk.feature.list() | Discover registered feature IDs |
cesdk.feature.get() | Get predicate chain for debugging |
Enable Features#
Use cesdk.feature.enable() to activate a feature with its default predicate behavior. The method accepts a single feature ID, an array of IDs, or a glob pattern.
// Enable delete feature with default predicatecesdk.feature.enable('ly.img.delete');You can enable multiple features at once by passing an array:
// Enable multiple features at oncecesdk.feature.enable(['ly.img.duplicate', 'ly.img.group']);Glob patterns allow you to enable all features matching a pattern. The * wildcard matches any sequence of characters:
// Enable all video features using glob patterncesdk.feature.enable('ly.img.video*');Disable Features#
Use cesdk.feature.disable() to hide features from the UI. Like enable(), it accepts single IDs, arrays, or glob patterns.
// Disable crop featurecesdk.feature.disable('ly.img.crop');Disable multiple features at once by passing an array:
// Disable multiple features at oncecesdk.feature.disable(['ly.img.notifications', 'ly.img.preview']);Use glob patterns to disable all features matching a pattern:
// Disable all transform features using glob patterncesdk.feature.disable('ly.img.transform*');Custom Predicates#
The cesdk.feature.set() method allows you to configure features with custom logic. You can pass a boolean value or a function predicate.
Boolean Predicates#
Passing true or false creates a terminal predicate that overrides any enable() or disable() calls:
// Set feature with boolean (terminal predicate)cesdk.feature.set('ly.img.fill', true);Function Predicates#
Function predicates receive a context object with engine, isPreviousEnable(), and defaultPredicate(). Use them for dynamic conditions based on selection or other state:
// Set feature with custom predicate based on selectioncesdk.feature.set('ly.img.duplicate', ({ engine }) => { return engine.block.findAllSelected().length > 0;});This predicate enables the duplicate feature only when at least one block is selected.
Extending Default Behavior#
You can build on a feature’s default predicate using defaultPredicate(). This lets you add conditions while preserving the built-in logic:
// Extend default predicate with additional conditioncesdk.feature.set('ly.img.delete', ({ defaultPredicate }) => { // Only allow delete in design mode return defaultPredicate() && engine.scene.getMode() === 'Design';});Layering Conditions#
Use isPreviousEnable() to chain with previously registered predicates. This enables layered conditions from multiple set() calls:
// Chain multiple predicates using isPreviousEnablecesdk.feature.set('ly.img.replace', ({ isPreviousEnable, engine }) => { const previousResult = isPreviousEnable(); const hasSelection = engine.block.findAllSelected().length > 0; return previousResult && hasSelection;});Evaluation Order#
When multiple predicates are registered for a feature, they evaluate in this order:
- Most recent
set()predicates run first - Older
set()predicates in reverse chronological order enable()/disable()state runs last
Boolean predicates are terminal and immediately return their value without continuing the chain. Function predicates control whether to continue by calling isPreviousEnable() or returning directly.
Glob Patterns#
All main Feature API methods support glob pattern matching for bulk operations. The * wildcard matches any sequence of characters within a segment.
Supported methods:
cesdk.feature.enable('ly.img.video.*')- Enable all video featurescesdk.feature.disable('ly.img.crop.*')- Disable all crop featurescesdk.feature.set('ly.img.navigation.*', predicate)- Set all navigation featurescesdk.feature.isEnabled('ly.img.video.*')- Check if ALL matching features are enabledcesdk.feature.list({ matcher: 'ly.img.video.*' })- List matching features
Check Feature Status#
Use cesdk.feature.isEnabled() to query if a feature is currently enabled:
// Check if a feature is enabledconst isDeleteEnabled = cesdk.feature.isEnabled('ly.img.delete');console.log('Delete feature enabled:', isDeleteEnabled);When using a glob pattern with isEnabled(), it returns true only if all matching features are enabled:
// Check if all video features are enabled (returns true only if ALL match)const allVideoEnabled = cesdk.feature.isEnabled('ly.img.video*');console.log('All video features enabled:', allVideoEnabled);Discover Features#
Use cesdk.feature.list() to get all registered feature IDs. You can filter with the optional matcher parameter:
// List all registered feature IDsconst allFeatures = cesdk.feature.list();console.log('All features:', allFeatures.slice(0, 10), '...');Filter the list with a glob pattern:
// List features matching a patternconst navigationFeatures = cesdk.feature.list({ matcher: 'ly.img.navigation*'});console.log('Navigation features:', navigationFeatures);Built-in Features#
CE.SDK includes many built-in features organized by category:
Navigation Features#
| Feature ID | Description |
|---|---|
ly.img.navigation.bar | Controls visibility of the Navigation Bar |
ly.img.navigation.back | Controls visibility of the “Back” button |
ly.img.navigation.close | Controls visibility of the “Close” button |
ly.img.navigation.undoRedo | Controls visibility of “Undo” and “Redo” buttons |
ly.img.navigation.zoom | Controls visibility of zoom controls |
ly.img.navigation.actions | Controls visibility of navigation actions |
Inspector Features#
| Feature ID | Description |
|---|---|
ly.img.inspector.bar | Controls visibility of the Inspector Bar |
ly.img.inspector.panel | Controls visibility of the Advanced Inspector |
ly.img.inspector.toggle | Controls presence of the Inspector Toggle button |
Canvas Features#
| Feature ID | Description |
|---|---|
ly.img.canvas.bar | Controls visibility of the Canvas Bar |
ly.img.canvas.menu | Controls visibility of the Canvas Menu |
Editing Features#
| Feature ID | Description |
|---|---|
ly.img.delete | Controls ability to delete blocks |
ly.img.duplicate | Controls ability to duplicate blocks |
ly.img.replace | Controls presence of the Replace button |
ly.img.group | Controls grouping functionality |
ly.img.placeholder | Controls Placeholder button visibility |
Video Features#
| Feature ID | Description |
|---|---|
ly.img.video.timeline | Controls visibility of the Video Timeline |
ly.img.video.clips | Controls visibility of video clips track |
ly.img.video.overlays | Controls visibility of overlays track |
ly.img.video.audio | Controls visibility of audio track |
ly.img.video.addClip | Controls ability to add clips |
ly.img.video.controls.* | Controls various video controls |
Text Features#
| Feature ID | Description |
|---|---|
ly.img.text.edit | Controls presence of the Edit button |
ly.img.text.typeface | Controls typeface dropdown |
ly.img.text.fontSize | Controls font size input |
ly.img.text.fontStyle | Controls bold/italic toggles |
ly.img.text.alignment | Controls text alignment |
ly.img.text.advanced | Controls advanced text options |
Effects Features#
| Feature ID | Description |
|---|---|
ly.img.fill | Controls Fill button |
ly.img.stroke | Controls Stroke controls |
ly.img.adjustment | Controls Adjustments button |
ly.img.filter | Controls Filter button |
ly.img.effect | Controls Effect button |
ly.img.blur | Controls Blur button |
ly.img.shadow | Controls Shadow button |
ly.img.crop | Controls Crop button |
Transform Features#
| Feature ID | Description |
|---|---|
ly.img.transform.position | Controls X/Y position controls |
ly.img.transform.size | Controls width/height controls |
ly.img.transform.rotation | Controls rotation controls |
ly.img.transform.flip | Controls flip controls |
Other Features#
| Feature ID | Description |
|---|---|
ly.img.dock | Controls visibility of the Dock |
ly.img.preview | Controls Preview button |
ly.img.page.add | Controls Add Page button |
ly.img.page.move | Controls page move buttons |
ly.img.page.resize | Controls Resize button |
ly.img.notifications | Controls notification toasts |
ly.img.notifications.undo | Controls undo notifications |
ly.img.notifications.redo | Controls redo notifications |
Troubleshooting#
Feature Not Visible#
If a feature doesn’t appear in the UI after calling enable():
- Check if a
set()call with a boolean is overriding it. Boolean predicates are terminal and take precedence. - Verify the feature ID spelling matches exactly.
- Confirm the feature is relevant for the current context (e.g., video features only appear in Video mode).
disable() Not Working#
If disable() doesn’t hide a feature:
- Check if a
set()predicate exists for that feature. Theset()predicates evaluate beforedisable(). - Use
cesdk.feature.get()to inspect the predicate chain.
Glob Pattern Not Matching#
If a glob pattern doesn’t affect expected features:
- Verify the pattern syntax is correct.
- Use
cesdk.feature.list({ matcher: 'your.pattern.*' })to see which features match. - Check that features are registered before applying the pattern.
API Reference#
| Method | Signature | Purpose |
|---|---|---|
cesdk.feature.enable() | enable(featureId: FeatureId | FeatureId[]): void | Enable features with default predicates |
cesdk.feature.disable() | disable(featureId: FeatureId | FeatureId[]): void | Disable features |
cesdk.feature.set() | set(featureId: FeatureId, enabled: boolean | FeaturePredicate): void | Set feature state with custom predicates |
cesdk.feature.isEnabled() | isEnabled(featureId: FeatureId, context?: FeatureContext): boolean | Check if feature is enabled |
cesdk.feature.list() | list(options?: { matcher?: string }): FeatureId[] | List registered feature IDs |
cesdk.feature.get() | get(featureId: FeatureId): FeaturePredicate[] | undefined | Get predicate chain for debugging |
Next Steps#
- Hide Elements - Hide UI elements without disabling functionality
- Navigation Bar - Customize navigation bar buttons
- Canvas Menu - Customize the canvas context menu
- Inspector Bar - Customize the inspector bar