Examples
App elements
Assets and media
Fundamentals
Design interaction
Intents
Drag and drop
Design elements
Localization
Content replacement
Autofill
Match data fields and autofill the current design using a hardcoded data table.
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 autofillSHELL -
Click the Preview URL link shown in the terminal to open the example in the Canva editor.
Example app source code
// For usage information, see the README.md file.import {Alert,Button,LoadingIndicator,Rows,Text,Title,} from "@canva/app-ui-kit";import type { DataField } from "@canva/design";import {autofillDesign,getDesignMetadata,requestDataFieldMatching,} from "@canva/design";import { useCallback, useEffect, useState } from "react";import * as styles from "styles/components.css";import { buildDataTable, TEAM_MEMBERS } from "./data";type Message = {text: string;tone: "positive" | "critical" | "warn";};export function App() {const [datasetFields, setDatasetFields] = useState<DataField[]>([]);const [isLoadingDataset, setIsLoadingDataset] = useState(true);const [isMatching, setIsMatching] = useState(false);const [isAutofilling, setIsAutofilling] = useState(false);const [message, setMessage] = useState<Message | null>(null);// Fields tagged for Autofill can change while this panel stays open (the user// tags/untags fields, or runs field matching), so re-read them rather than// trusting a one-time snapshot.const refreshDatasetFields = useCallback(async () => {try {const metadata = await getDesignMetadata();setDatasetFields(metadata.dataset ?? []);} finally {setIsLoadingDataset(false);}}, []);useEffect(() => {void refreshDatasetFields();}, [refreshDatasetFields]);const handleMatchFields = async () => {setIsMatching(true);setMessage(null);try {// Offers this example's field labels as sample data the user can match// against tagged elements in the design.await requestDataFieldMatching({sampleData: buildDataTable(TEAM_MEMBERS),});await refreshDatasetFields();setMessage({ text: "Field matching updated.", tone: "positive" });} catch (err) {setMessage({text: err instanceof Error ? err.message : "Field matching failed.",tone: "critical",});} finally {setIsMatching(false);}};const handleAutofill = async () => {setIsAutofilling(true);setMessage(null);try {const response = await autofillDesign({dataTable: buildDataTable(TEAM_MEMBERS),});if (response.status === "success") {setMessage({text: "Design autofilled successfully!",tone: "positive",});} else {setMessage({text: "No fields in this design are tagged for Autofill. Tag fields using the design's Autofill panel, then try again.",tone: "warn",});}} catch (err) {setMessage({text: err instanceof Error ? err.message : "Autofill failed.",tone: "critical",});} finally {setIsAutofilling(false);}};return (<div className={styles.scrollContainer}><Rows spacing="2u"><Title>Autofill</Title><Text>Match this app's data fields against the design's tagged elements,then autofill the design with a hardcoded data table.</Text>{isLoadingDataset ? (<LoadingIndicator size="small" />) : datasetFields.length === 0 ? (<Text tone="secondary">No fields are tagged for Autofill in this design yet.</Text>) : (<Rows spacing="0.5u"><Text size="small" tone="secondary">Tagged fields:</Text>{datasetFields.map((field) => (<Text key={field.label} size="small">{`• ${field.label} (${field.type})`}</Text>))}</Rows>)}<Buttonvariant="secondary"onClick={handleMatchFields}loading={isMatching}stretch>Match data fields</Button><Buttonvariant="primary"onClick={handleAutofill}loading={isAutofilling}stretch>Autofill design</Button>{message && <Alert tone={message.tone}>{message.text}</Alert>}</Rows></div>);}
TYPESCRIPT
// For usage information, see the README.md file.import type {ColumnConfig,DataTable,DataTableRow,} from "@canva/intents/data";export type TeamMember = {name: string;role: string;location: string;};// A small hardcoded dataset standing in for data you'd otherwise fetch from a// Data Connector (see the intents/request_data_table example) or an external API.export const TEAM_MEMBERS: TeamMember[] = [{ name: "Ana Silva", role: "Product Designer", location: "Sydney" },{ name: "Wei Chen", role: "Engineer", location: "Singapore" },{ name: "Priya Nair", role: "Engineer", location: "Bengaluru" },{ name: "Tom Baker", role: "Marketing Lead", location: "London" },{ name: "Sofia Reyes", role: "Customer Success", location: "Austin" },];const COLUMN_CONFIGS: ColumnConfig[] = [{ name: "Name", type: "string" },{ name: "Role", type: "string" },{ name: "Location", type: "string" },];// `autofillDesign` and `requestDataFieldMatching` accept the same `DataTable`// shape as the Data Connector intent, so it's imported from `@canva/intents/data`// rather than redeclared here.export function buildDataTable(members: TeamMember[]): DataTable {const rows: DataTableRow[] = members.map((member) => ({cells: [{ type: "string", value: member.name },{ type: "string", value: member.role },{ type: "string", value: member.location },],}));return { columnConfigs: COLUMN_CONFIGS, rows };}
TYPESCRIPT
// For usage information, see the README.md file.import { AppUiProvider } from "@canva/app-ui-kit";import { createRoot } from "react-dom/client";import { App } from "./app";import "@canva/app-ui-kit/styles.css";import type { DesignEditorIntent } from "@canva/intents/design";import { prepareDesignEditor } from "@canva/intents/design";async function render() {const root = createRoot(document.getElementById("root") as Element);root.render(<AppUiProvider><App /></AppUiProvider>,);}const designEditor: DesignEditorIntent = { render };prepareDesignEditor(designEditor);// Hot Module Replacement for development (automatically reloads the app when changes are made)if (module.hot) {module.hot.accept("./app", render);}
TYPESCRIPT
# AutofillThis example demonstrates how to match data fields and autofill the currentdesign using `requestDataFieldMatching` and `autofillDesign` from`@canva/design`, against a hardcoded data table (no Data Connector needed).The hardcoded table is typed with the `DataTable` type from `@canva/intents/data`— the same `DataTable` shape a Data Connector's `getDataTable` would return.The app implements a single **Design Editor** intent. It reads the design'scurrently tagged fields with `getDesignMetadata`. "Match data fields" calls`requestDataFieldMatching` with a small hardcoded sample table so the user canmatch this app's field labels ("Name", "Role", "Location") against taggedelements in the design. "Autofill design" calls `autofillDesign` with the samehardcoded table to fill in those tagged elements.For API reference docs and instructions on running this example, see:<https://www.canva.dev/docs/apps/examples/autofill/>.Related examples: see `intents/request_data_table` for fetching a data tablefrom a Data Connector instead of a hardcoded one, and `design_interaction/brand_templates`for selecting and applying a brand template before autofilling it.NOTE: This example differs from what is expected for public apps to pass a Canva review:- **Preview/beta API**: `autofillDesign` and `getDesignMetadata` are `@beta`APIs, and `requestDataFieldMatching` isn't yet available in this example'spinned `@canva/design` version — it will ship in a subsequent beta release.Check the latest API status in the docs before relying on these in aproduction app.- **Static/hardcoded data**: The data used for matching and autofilling is afixed, hardcoded table. Production apps should use real data, typicallyfetched from a Data Connector (see `intents/request_data_table`) or anexternal API.- **Localization**: Text content is hardcoded in English. Production appsrequire proper internationalization using the `@canva/app-i18n-kit` packagefor multi-language support.- **Error handling**: Error handling is simplified for demonstration.Production apps must implement comprehensive error handling with clear userfeedback and graceful failure modes.
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)