> ## Documentation Index > Fetch the complete documentation index at: https://www.canva.dev/docs/apps/llms.txt > Use this file to discover all available pages before exploring further. # Multiple intents Example app demonstrating design editor and content publisher intents together ## Running this example To run this example locally: 1. If you haven't already, create a new app in the [Developer Portal](https://www.canva.com/developers/apps). For more information, refer to our [Quickstart guide](https://www.canva.dev/docs/apps/quickstart/). 2. In your app's configuration on the [Developer Portal](https://www.canva.com/developers/apps), ensure the "Development URL" is set to `http://localhost:8080`. 3. Clone the starter kit: ```shell git clone https://github.com/canva-sdks/canva-apps-sdk-starter-kit.git cd canva-apps-sdk-starter-kit ``` 4. Install dependencies: ```shell npm install ``` 5. Run the example: ```shell npm run start:example implement_multiple_intents ``` 6. Click the **Preview URL** link shown in the terminal to open the example in the Canva editor. ## Example app source code ```json { "$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 } } } ``` ```typescript // 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 defined async function getPublishConfiguration(): Promise { 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 options function 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(
This is the content publisher intent portion of the app. Here you would render an interface for controlling the publishing settings.
, ); } // Render the preview UI showing how the content will appear after publishing function renderPreviewUi(request: RenderPreviewUiRequest) { const root = createRoot(document.getElementById("root") as Element); // TODO: You should update this value to match the visuals you're hoping to achieve with your export preview // Image width + padding + border const previewWidth = 400 + 32 + 2; root.render(
This is the content publisher intent portion of the app. Here you would render a preview for visualizing how the design would appear in the publishing platform.
, ); } // Handle the actual publishing when the user clicks the publish button // In production, this should make API calls to your platform async function publishContent( request: PublishContentRequest, ): Promise { // 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 post externalUrl: "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(
This is the design editor intent portion of the app.
, ); } const designEditor: DesignEditorIntent = { render }; export default designEditor; ```
```markdown # Implement Multiple intents This 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: . 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 ```
## API reference * [App UI Kit](https://www.canva.dev/docs/apps/app-ui-kit/) * [`prepareContentPublisher`](https://www.canva.dev/docs/apps/api/preview/intents-content-prepare-content-publisher/) * [`prepareDesignEditor`](https://www.canva.dev/docs/apps/api/preview/intents-design-prepare-design-editor/) * [`requestOpenExternalUrl`](https://www.canva.dev/docs/apps/api/latest/platform-request-open-external-url/) ## Need help? * Join our [Community Forum](https://community.canva.dev/) * Report issues with this example on [GitHub](https://github.com/canva-sdks/canva-apps-sdk-starter-kit/issues)