# Lock the Template

Set up a two-surface integration where template creators have full editing access while template adopters can only modify designated areas.

![Lock the Template](/docs/cesdk/_astro/browser.hero.B1rc32Rd_2leXOy.webp)

10 mins

estimated time

Live Demo[

Download](https://github.com/imgly/cesdk-web-examples/archive/refs/heads/main.zip)[

StackBlitz](https://stackblitz.com/~/github.com/imgly/cesdk-web-examples/tree/main/guides-create-templates-lock-browser)[

GitHub](https://github.com/imgly/cesdk-web-examples/tree/main/guides-create-templates-lock-browser)

Many integrations need two different editing experiences: one for designers who build templates, and one for end users who customize them. The Creator and Adopter roles make this possible—same CE.SDK, different permissions based on who’s using it. For detailed scope configuration patterns, see [Lock Content](vue/rules/lock-content-9fa727/) .

In the live example, the headline text is pre-selected and the Placeholder panel is open, showing the scope settings that control what Adopters can edit. Toggle the role to Adopter and try selecting the logo to see the restrictions in action.

```
import type { EditorPlugin, EditorPluginContext } from '@cesdk/cesdk-js';import packageJson from './package.json';
/** * CE.SDK Plugin: Lock the Template * * This example demonstrates the two-surface pattern for template workflows: * - Creator role: Full editing access for designers building templates * - Adopter role: Restricted access for users customizing templates */class Example implements EditorPlugin {  name = packageJson.name;
  version = packageJson.version;
  async initialize({ cesdk }: EditorPluginContext): Promise<void> {    if (!cesdk) {      throw new Error('CE.SDK instance is required for this plugin');    }
    // Initialize CE.SDK with Design mode    await cesdk.addDefaultAssetSources();    await cesdk.addDemoAssetSources({      sceneMode: 'Design',      withUploadAssetSources: true    });    await cesdk.createDesignScene();
    const engine = cesdk.engine;
    // Get the page and set dimensions    const page = engine.block.findByType('page')[0];    engine.block.setWidth(page, 800);    engine.block.setHeight(page, 500);
    // Create a brand template with a logo and headline    const logoBlock = await engine.block.addImage(      'https://img.ly/static/ubq_samples/imgly_logo.jpg',      { size: { width: 120, height: 30 } }    );    engine.block.appendChild(page, logoBlock);    engine.block.setPositionX(logoBlock, 40);    engine.block.setPositionY(logoBlock, 40);    engine.block.setName(logoBlock, 'Logo');
    const headlineBlock = engine.block.create('text');    engine.block.replaceText(headlineBlock, 'Edit this headline');    engine.block.setWidth(headlineBlock, 720);    engine.block.setHeightMode(headlineBlock, 'Auto');    engine.block.setFloat(headlineBlock, 'text/fontSize', 48);    engine.block.setEnum(headlineBlock, 'text/horizontalAlignment', 'Center');    engine.block.appendChild(page, headlineBlock);    engine.block.setPositionX(headlineBlock, 40);    engine.block.setPositionY(headlineBlock, 200);    engine.block.setName(headlineBlock, 'Headline');
    // Configure which elements Adopters can edit    // Enable selection and text editing on the headline    engine.block.setScopeEnabled(headlineBlock, 'editor/select', true);    engine.block.setScopeEnabled(headlineBlock, 'text/edit', true);
    // Leave all scopes disabled on the logo (default state)    // This prevents Adopters from selecting or modifying the logo
    // The Creator role ignores all scope restrictions    engine.editor.setRole('Creator');
    // Add a role toggle to the navigation bar (engine calls are reactive)    cesdk.ui.registerComponent(      'ly.img.roleToggle.navigationBar',      ({ builder }) => {        const role = engine.editor.getRole();        builder.ButtonGroup('role-toggle', {          children: () => {            builder.Button('creator', {              label: 'Creator',              isActive: role === 'Creator',              onClick: () => engine.editor.setRole('Creator')            });            builder.Button('adopter', {              label: 'Adopter',              isActive: role === 'Adopter',              onClick: () => {                // Close the placeholder panel since Adopters can't configure scopes                cesdk.ui.closePanel(                  '//ly.img.panel/inspector/placeholderSettings'                );                engine.editor.setRole('Adopter');              }            });          }        });      }    );
    cesdk.ui.setNavigationBarOrder([      'ly.img.undoRedo.navigationBar',      'ly.img.spacer',      'ly.img.roleToggle.navigationBar',      'ly.img.spacer'    ]);
    await engine.scene.zoomToBlock(page, { padding: 40 });
    // Select the headline and open the placeholder panel so users see the scope settings    engine.block.select(headlineBlock);    setTimeout(() => {      cesdk.ui.openPanel('//ly.img.panel/inspector/placeholderSettings');    }, 300);  }}
export default Example;
```

This guide covers how to understand the two-surface pattern, configure roles for different user groups, and set up scope restrictions that control what Adopters can edit.

## Understanding the Two-Surface Pattern[#](#understanding-the-two-surface-pattern)

Template-based workflows typically involve two distinct user groups with different needs:

| Surface | Users | Role | What they can do |
| --- | --- | --- | --- |
| Creator Surface | Designers, admins | `Creator` | Full editing—build templates, set locks |
| Adopter Surface | End users, marketers | `Adopter` | Restricted editing—only modify unlocked areas |

This separation protects design intent while enabling customization. The Creator role ignores all locks, giving full access. The Adopter role respects locks, restricting users to what’s explicitly allowed.

## Setting Up the Creator Surface[#](#setting-up-the-creator-surface)

The Creator surface is where templates are built. We use `engine.editor.setRole('Creator')` to give designers unrestricted access.

```
// The Creator role ignores all scope restrictionsengine.editor.setRole('Creator');
```

In Creator mode, all operations are permitted regardless of scope settings. This is where designers build the template layout, configure which elements should be editable, set scope restrictions using `engine.block.setScopeEnabled()`, and save the template for distribution.

## Setting Up the Adopter Surface[#](#setting-up-the-adopter-surface)

The Adopter surface is where templates are used. Call `engine.editor.setRole('Adopter')` to enforce the restrictions configured by creators. In Adopter mode, users can only interact with blocks that have the appropriate scopes enabled. The Adopter role respects all lock configurations, ensuring brand consistency and design intent are maintained.

## When to Use This Pattern[#](#when-to-use-this-pattern)

This two-surface approach works well for:

*   **Brand template systems**: Marketing teams customize approved templates
*   **Design approval workflows**: Creators build, reviewers can’t accidentally modify
*   **Self-service customization**: End users personalize within guardrails
*   **White-label products**: Customers can only edit designated areas

For simpler use cases where all users have the same permissions, you may not need separate surfaces.

## Configuring What Users Can Edit[#](#configuring-what-users-can-edit)

The scope system controls what Adopters can modify. In Creator mode, we enable specific scopes on blocks that should be editable.

```
// Configure which elements Adopters can edit// Enable selection and text editing on the headlineengine.block.setScopeEnabled(headlineBlock, 'editor/select', true);engine.block.setScopeEnabled(headlineBlock, 'text/edit', true);
// Leave all scopes disabled on the logo (default state)// This prevents Adopters from selecting or modifying the logo
```

When Adopters load this template, they can edit the headline text but nothing else. The `editor/select` scope must be enabled for users to interact with a block at all. For comprehensive scope configuration patterns, see [Lock Content](vue/rules/lock-content-9fa727/) .

## Configuring Scopes in the Editor UI[#](#configuring-scopes-in-the-editor-ui)

Designers can also configure scopes visually without writing code. In Creator mode, select any block and open the Placeholder panel in the inspector. This panel provides toggles for each scope:

*   **Allow selecting** (`editor/select`): Users can click to select the block
*   **Allow editing text** (`text/edit`): Users can modify text content
*   **Allow changing fill** (`fill/change`): Users can swap images or change colors
*   **Allow moving** (`layer/move`): Users can reposition the block
*   **Allow deleting** (`lifecycle/destroy`): Users can remove the block

Changes made in the Placeholder panel are equivalent to calling `engine.block.setScopeEnabled()` programmatically. When the template is saved, these settings persist and apply when Adopters load the template.

## Adding a Role Toggle[#](#adding-a-role-toggle)

Add a segmented control to the navigation bar that switches between Creator and Adopter modes. Engine calls inside the builder are automatically reactive—the component re-renders when the role changes.

```
// Add a role toggle to the navigation bar (engine calls are reactive)cesdk.ui.registerComponent(  'ly.img.roleToggle.navigationBar',  ({ builder }) => {    const role = engine.editor.getRole();    builder.ButtonGroup('role-toggle', {      children: () => {        builder.Button('creator', {          label: 'Creator',          isActive: role === 'Creator',          onClick: () => engine.editor.setRole('Creator')        });        builder.Button('adopter', {          label: 'Adopter',          isActive: role === 'Adopter',          onClick: () => {            // Close the placeholder panel since Adopters can't configure scopes            cesdk.ui.closePanel(              '//ly.img.panel/inspector/placeholderSettings'            );            engine.editor.setRole('Adopter');          }        });      }    });  });
cesdk.ui.setNavigationBarOrder([  'ly.img.undoRedo.navigationBar',  'ly.img.spacer',  'ly.img.roleToggle.navigationBar',  'ly.img.spacer']);
```

## Troubleshooting[#](#troubleshooting)

| Issue | Cause | Solution |
| --- | --- | --- |
| Adopter can edit everything | Wrong role or scopes not configured | Verify role is `Adopter` and scopes are set in Creator mode |
| Adopter can’t edit anything | `editor/select` scope not enabled | Enable `editor/select` on blocks users should interact with |
| Creator can’t set locks | Wrong role | Switch to Creator role before configuring scopes |
| Changes not persisting | Template not saved after scope changes | Save template after configuring scopes in Creator mode |

## API Reference[#](#api-reference)

| Method | Description |
| --- | --- |
| `engine.editor.setRole(role)` | Set the editing role (`'Creator'`, `'Adopter'`, or `'Viewer'`) |
| `engine.editor.getRole()` | Get the current editing role |
| `engine.block.setScopeEnabled(block, scope, enabled)` | Enable or disable a scope on a block |
| `engine.block.isScopeEnabled(block, scope)` | Check if a scope is enabled on a block |
| `cesdk.ui.registerComponent(id, renderFn)` | Register a custom UI component |
| `builder.ButtonGroup(id, { children })` | Create a segmented control |
| `builder.Button(id, { label, isActive, onClick })` | Create a button |

### Common Scopes[#](#common-scopes)

| Scope | Description |
| --- | --- |
| `'editor/select'` | Allow selecting the block (required for any interaction) |
| `'fill/change'` | Allow changing the block’s fill (images, colors) |
| `'text/edit'` | Allow editing text content |
| `'text/character'` | Allow changing text formatting (font, size, color) |
| `'layer/move'` | Allow moving the block |
| `'layer/resize'` | Allow resizing the block |
| `'layer/rotate'` | Allow rotating the block |
| `'layer/crop'` | Allow cropping the block |
| `'lifecycle/destroy'` | Allow deleting the block |

---



[Source](https:/img.ly/docs/cesdk/vue/create-templates/import-e50084)