Design Editor intent upgrade guide
This guide explains all of the code changes required to upgrade from the legacy direct render pattern to the new Design Editor intent pattern. The Design Editor intent provides a standardized way to render apps within the Canva editor and ensures better compatibility with future Canva features.
Automated migration tool
You can use the Canva CLI automated migration tool to handle most of the required changes. The CLI automatically updates:
- Package installation for
@canva/intents
- Import statements to include
prepareDesignEditor
- Render function to use
async
/await
- Code structure to wrap render logic with
prepareDesignEditor()
- App manifest configuration in Developer Portal
For detailed CLI usage, see the Canva CLI documentation.
Run the migration tool
-
If you haven't already, install the Canva CLI:
npm install -g @canva/cli@latestSHELL -
In your app directory, run the migration command:
canva apps migrate design-editor-intentSHELL
After running the automated migration, review the changes and complete any manual steps outlined in the following sections.
Manual migration steps
The following sections explain the specific code changes if you prefer to upgrade manually or need to handle cases not covered by the automated tool.
Install the @canva/intents package
The Design Editor intent requires the @canva/intents
package. Install it by running:
npm install @canva/intents@latest
Update your app's index file
The main code change involves updating how your app initializes and renders its UI. This typically happens in your src/index.tsx
file.
Before: Direct render pattern
In the legacy pattern, apps directly called the render function:
import { createRoot } from "react-dom/client";import { App } from "./app";const root = createRoot(document.getElementById("root"));function render() {root.render(<App />);}render(); // Direct function call
After: Design Editor intent pattern
With the Design Editor intent, you wrap your render logic with prepareDesignEditor()
:
import { createRoot } from "react-dom/client";import { App } from "./app";import { prepareDesignEditor } from "@canva/intents/design";const root = createRoot(document.getElementById("root"));async function render() {root.render(<App />);}prepareDesignEditor({ render }); // Wrap render function
The key changes are:
- Import
prepareDesignEditor
from@canva/intents/design
- Make render function async by adding the
async
keyword - Replace direct render call with
prepareDesignEditor({ render })
Enable the Design Editor intent
After updating your code, you need to enable the Design Editor intent in your app's configuration.
You can configure intents for your app with either the Developer Portal or the Canva CLI:
To enable the Design Editor intent:
- Navigate to an app on the Your apps(opens in a new tab or window) page.
- On the Compatibility page, find the Intents section.
- Enable the Design Editor switch.
-
Set up your app to use the Canva CLI to manage settings using the canva-app.json file.
-
Set the
intent.design_editor
property to be enrolled. For more information, see canva-app.json.{"intent": {"design_editor": {"enrolled": true}}}JSON -
Push the configuration to the Developer Portal:
canva apps pushSHELL
Advanced: Custom render implementation
If your app has a more complex rendering setup, you may need to adapt the pattern accordingly. The render
function passed to prepareDesignEditor()
can contain any initialization logic your app needs:
import { createRoot } from "react-dom/client";import { AppUiProvider } from "@canva/app-ui-kit";import { prepareDesignEditor } from "@canva/intents/design";import { App } from "./app";import "@canva/app-ui-kit/styles.css";prepareDesignEditor({render: async () => {// Find the root elementconst rootElement = document.getElementById("root");if (!rootElement) {throw new Error("Unable to find element with id of 'root'");}// Create React rootconst root = createRoot(rootElement);// Render your app with any providersroot.render(<AppUiProvider><App /></AppUiProvider>);},});
Update tests
If your app has tests that verify the rendering behavior, you'll need to update them to account for the new pattern:
Before:
import { render } from "./index";render(); // Called directly in tests
After:
import { prepareDesignEditor } from "@canva/intents/design";// Tests should mock prepareDesignEditor or test the render function passed to it
Verify the migration
After completing the migration:
-
Build your app to check for TypeScript errors:
npm run buildSHELL -
Preview your app in the Canva editor:
canva apps previewSHELL -
Test functionality by opening your app in Canva and verifying it loads correctly.