Examples
App elements
Assets and media
Design interaction
Drag and drop
Design elements
Localization
Content replacement
Multiple Intents Example
Example app demonstrating design editor and content publisher intents together
Running this example
To run this example locally:
-
If you haven't already, create a new app in the Developer Portal(opens in a new tab or window). For more information, refer to our Quickstart guide.
-
In your app's configuration on the Developer Portal(opens in a new tab or window), ensure the "Development URL" is set to
http://localhost:8080. -
Clone the starter kit:
git clone https://github.com/canva-sdks/canva-apps-sdk-starter-kit.gitcd canva-apps-sdk-starter-kitSHELL -
Install dependencies:
npm installSHELL -
Run the example:
npm run start implement_multiple_intentsSHELL -
Click the Preview URL link shown in the terminal to open the example in the Canva editor.
Example app source code
{"$schema": "https://www.canva.dev/schemas/app/v1/manifest-schema.json","manifest_schema_version": 1,"runtime": {"permissions": [{"name": "canva:design:content:read","type": "mandatory"},{"name": "canva:design:content:write","type": "mandatory"}]},"intent": {"content_publisher": {"enrolled": true},"design_editor": {"enrolled": true}}}
JSON
// For usage information, see the README.md file.// This root index file contains the prepare function calls that initialize each intent.// Each intent entrypoint is respondible for exporting the intent contract implementation.import { prepareContentPublisher } from "@canva/intents/content";import { prepareDesignEditor } from "@canva/intents/design";import contentPublisher from "./intents/content_publisher";import designEditor from "./intents/design_editor";prepareContentPublisher(contentPublisher);prepareDesignEditor(designEditor);
TYPESCRIPT
// For usage information, see the README.md file.import type {ContentPublisherIntent,GetPublishConfigurationResponse,PublishContentRequest,PublishContentResponse,RenderPreviewUiRequest,RenderSettingsUiRequest,} from "@canva/intents/content";import { createRoot } from "react-dom/client";import "@canva/app-ui-kit/styles.css";import { AppUiProvider, Box, Button } from "@canva/app-ui-kit";import { Rows, Text } from "@canva/app-ui-kit";import * as styles from "styles/components.css";import { requestOpenExternalUrl } from "@canva/platform";// This example demonstrates how multiple intents can be implemented within a single Canva app.// For a more detailed example of the Content Publisher Intent, refer to the content_publisher_intent example.// Define the output types (publishing formats) available to users// Canva automatically displays a dropdown selector when more than one output type is definedasync function getPublishConfiguration(): Promise<GetPublishConfigurationResponse> {return {status: "completed",outputTypes: [{id: "post",displayName: "Output type: Post",mediaSlots: [{id: "media",displayName: "Media",fileCount: { exact: 1 },accepts: {image: {format: "png",// Social media post aspect ratio range (portrait to landscape)aspectRatio: { min: 4 / 5, max: 1.91 / 1 },},},},],},],};}// Render the settings UI where users configure publishing optionsfunction renderSettingsUi(request: RenderSettingsUiRequest) {const root = createRoot(document.getElementById("root") as Element);const openDocs = async () => {await requestOpenExternalUrl({url: "https://www.canva.dev/docs/apps/content-publisher/",});};root.render(<AppUiProvider><div className={styles.scrollContainer}><Rows spacing="2u"><Text>This is the content publisher intent portion of the app. Here youwould render an interface for controlling the publishing settings.</Text><Button variant="primary" onClick={openDocs}>Open Content Publisher Intent docs</Button></Rows></div></AppUiProvider>,);}// Render the preview UI showing how the content will appear after publishingfunction renderPreviewUi(request: RenderPreviewUiRequest) {const root = createRoot(document.getElementById("root") as Element);root.render(<AppUiProvider><div className={styles.previewContainer}><BoxclassName={styles.previewWrapper}background="surface"borderRadius="large"padding="2u"border="standard"><Rows spacing="2u"><Text>This is the content publisher intent portion of the app. Here youwould render a preview for visualising how the design would appearin the publishing platform.</Text></Rows></Box></div></AppUiProvider>,);}// Handle the actual publishing when the user clicks the publish button// In production, this should make API calls to your platformasync function publishContent(request: PublishContentRequest,): Promise<PublishContentResponse> {// Replace this with your actual API integration// Example: Upload media to your platform and create a post// const uploadedMedia = await uploadToYourPlatform(params.outputMedia);// const post = await createPostOnYourPlatform({// media: uploadedMedia,// caption: JSON.parse(params.publishRef).caption// });return {status: "completed",externalId: "1234567890", // Your platform's unique identifier for this postexternalUrl: "https://example.com/posts/1234567890", // Link to view the published content};}const contentPublisher: ContentPublisherIntent = {renderSettingsUi,renderPreviewUi,getPublishConfiguration,publishContent,};export default contentPublisher;
TYPESCRIPT
import "@canva/app-ui-kit/styles.css";import type { DesignEditorIntent } from "@canva/intents/design";import { AppUiProvider } from "@canva/app-ui-kit";import { createRoot } from "react-dom/client";import { Button, Rows, Text } from "@canva/app-ui-kit";import { requestOpenExternalUrl } from "@canva/platform";import * as styles from "styles/components.css";// This example demonstrates how multiple intents can be implemented within a single Canva app.// For a more detailed example of the Design Editor Intent and all its capabilities, refer to other app examples in this starter kit.async function render() {const root = createRoot(document.getElementById("root") as Element);const openDocs = async () => {await requestOpenExternalUrl({url: "https://www.canva.dev/docs/apps/design-editor/",});};// Render the design editor intent UI// This is a simple example to demonstrate how multiple intents can be implemented in the same app.root.render(<AppUiProvider><div className={styles.scrollContainer}><Rows spacing="2u"><Text>This is the design editor intent portion of the app.</Text><Button variant="primary" onClick={openDocs}>Open Design Editor Intent docs</Button></Rows></div></AppUiProvider>,);}const designEditor: DesignEditorIntent = { render };export default designEditor;
TYPESCRIPT
# Implement Multiple intentsThis example demonstrates how to structure an app to implement multiple intents in the same code. The app is a combination of the design editor starter example and the content publisher example.This example demonstrates our recommeneded code structure for multiple intent apps. The root index file `src/index.tsx` calls the prepare function for each implemented intent.There's a `src/intents` folder, and within this folder there's one folder for each implemented intent. The index file of these folders implements the intent contract.For example, `src/index.tsx` calls `prepareDesignEditor` with the `DesignEditorIntent` implementation imported from `src/intents/design_editor/index.tsx`, and calls `prepareContentPublisher` with the `ContentPublisherIntent` implementation imported from `src/intents/content_publisher/index.tsx`.This example has a `canva-app.json` app config file with both intents enrolled.For API reference docs and instructions on running this example, see: <https://www.canva.dev/docs/apps/examples/multiple-intents/>.NOTE: This example differs from what is expected for public apps to pass a Canva review:- Error handling is simplified for demonstration. Production apps must implement comprehensive error handling with clear user feedback and graceful failure modes- Accessibility features aren't fully implemented. Production apps must meet WCAG 2.0 AA standards with proper keyboard navigation and ARIA labels- Internationalization is not implemented. Production apps must support multiple languages using the `@canva/app-i18n-kit` package to pass Canva review requirements
MARKDOWN
API reference
Need help?
- Join our Community Forum(opens in a new tab or window)
- Report issues with this example on GitHub(opens in a new tab or window)