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 change to wrap render logic in an object to implement the
DesignEditorIntenttype. - Code structure changes to match the recommended practices for intents by creating
src/intents/design_editor/index.tsx. - Code change to call
prepareDesignEditor()in thesrc/index.tsxfile which imports the implementation of theDesignEditorIntenttype. - 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. We recommend this happens in a new src/intents/design_editor/index.tsx file, which is imported from src/index.tsx.
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 implement the intent contract in src/intents/design_editor/index.tsx and call prepareDesignEditor() in src/index.tsx:
import type { DesignEditorIntent } from "@canva/intents/design";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 />);}const designEditor: DesignEditorIntent = { render };export default designEditor; // default export the intent contract
This new file should be imported from src/index.tsx:
import { prepareDesignEditor } from "@canva/intents/design";import designEditor from "./intents/design_editor";prepareDesignEditor(designEditor);
The key changes are:
- Import
prepareDesignEditorfrom@canva/intents/designinsrc/index.tsx - Export the designEditor implementation object from
src/intents/design_editor/index.tsx - Make render function async by adding the
asynckeyword - Replace direct render call with
prepareDesignEditor(designEditor)
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 via the Your apps(opens in a new tab or window) page.
- On the Intents page, find the "Available intents" section.
- For the "Design Editor" intent, click Set up.
- In the "Implement in your code" dialog that appears, click Done. This guide walks you through implementing the intent in your code.
-
Set up your app to use the Canva CLI to manage settings using the canva-app.json file.
-
Set the
intent.design_editorproperty 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 in the DesignEditorIntent can contain any initialization logic your app needs:
import type { DesignEditorIntent } from "@canva/intents/design";import { createRoot } from "react-dom/client";import { AppUiProvider } from "@canva/app-ui-kit";import { App } from "./app";import "@canva/app-ui-kit/styles.css";async function render() {// 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>);};const designEditor: DesignEditorIntent = { render };export default designEditor; // default export the intent contract
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.