Creating data providers
Canva has a number of data-driven features, such as Bulk Create and charts. These features help users streamline their design workflows, create stunning visualizations, and more.
Users can import data from a number of data sources, such as CSV files, and it's also possible for apps to become data sources.
Use-cases
- Share interesting and useful datasets with the world.
- Create trusted data sources that reduce errors and misinformation.
- Save hours of effort by generating designs from a dataset.
Example apps
Here are some examples of apps that act as data sources:
- An app for a real estate agency that exposes property data. The real estate agents could then use that data to generate designs for the listings.
- An app for a not-for-profit organization that exposes data relating to their impact. The staff could then use that data to keep the data in their messaging aligned.
Terminology
- Provider - A data source that Canva features or apps can import data from.
- Consumer - A Canva feature or app that imports data from a provider. The consumer can then use that data however it wants — for example, to render a chart.
- Data table - The data structure that providers must use when exposing data. By conforming to this structure, all providers are automatically compatible with all consumers.
The anatomy of data tables
A data table shares a number of similarities with spreadsheets:
- They have columns
- Each column has a name
- Each column has a list of values
This is an example of a data table that contains a list of dog breeds:
In code, a data table is a plain JavaScript object with a name and an array of columns:
{"name": "Dog breeds","columns": []}
Understanding columns
A column is a plain JavaScript object with a data type, a name, and an array of values:
{"type": "string","name": "Name","values": ["Golden retriever", "Labrador retriever", "Flat-coated retriever"]}
Supported data types
The type
property can be set to any of the following values:
The data type of the values must match the data type specified in the type
property.
Empty cells
You can include undefined
values in the values
array. This creates an empty cell and is the only instance where the value's data type doesn't have to match the data type in the type
property.
How to handle data requests
Step 1: Enable the Data API
- Log in to the Developer Portal.
- Navigate to an app via the Your apps page.
- Enable Data Provider.
Step 2: Create a data table
Import the DataTable
type:
import { DataTable } from "@canva/preview/data";
Create an object that conforms to the DataTable
type:
const DATA_TABLE: DataTable = {name: "Dog breeds",columns: [{type: "string",name: "name",values: ["Golden retriever","Labrador retriever","Flat-coated retriever","Goldendoodle",],},{type: "string",name: "country",values: ["Scotland", "United Kingdom", "England", "Australia"],},{ type: "number", name: "weight", values: [35, 35, 30, 25] },{type: "boolean",name: "isPureBreed",values: [true, true, true, false],},],};
In this case, the data table is hard-coded, but an actual app would either:
- Fetch the data from a backend
- Create the data at runtime
Step 3: Send the data table to the consumer
When the app loads, register a callback with the onSelectDataTable
method:
import { onSelectDataTable } from "@canva/preview/data";React.useEffect(() => {onSelectDataTable(async (options) => {options.selectDataTable(DATA_TABLE);});}, []);
This callback receives a selectDataTable
method. This method accepts a data table as its only argument and sends this data table to Canva.
Because the app doesn't have a UI, the App
component can return undefined
:
export function App() {React.useEffect(() => {onSelectDataTable((options) => {options.selectDataTable(DATA_TABLE);});}, []);}
How to prompt users for input
Step 1: Render a UI
In the App
component, return a UI that lets the user select or configure the data to send to Canva — the exact UI will depend on the shape and requirements of the underlying dataset.
In the following code sample, the user is shown a list of cities:
import React from "react";import { DataTable, onSelectDataTable } from "@canva/preview/data";export function App() {return (<div><div>Choose a location</div><div><button>Brisbane</button></div><div><button>Melbourne</button></div><div><button>Sydney</button></div></div>);}
Step 2: Handle the provider's selection
Import the SelectDataTableRequest
type:
import {DataTable,SelectDataTableRequest,onSelectDataTable,} from "@canva/preview/data";
This type represents the callback that's registered with the onSelectDataTable
method.
Use the useState
hook to store the callback:
const [callback, setCallback] = React.useState<SelectDataTableRequest | undefined>();React.useEffect(() => {onSelectDataTable((options) => {setCallback(options);});}, []);
This makes it easier to call the selectDataTable
method in response to UI-driven events, such as a button click.
Step 3: Send a data table to the consumer
When a user has selected or configured the data to send to Canva, call the selectDataTable
method and pass through the relevant data table.
In the following code sample, the user can click a button to get a data table from an array:
import React from "react";import {DataTable,SelectDataTableRequest,onSelectDataTable,} from "@canva/preview/data";const DATA_TABLES: DataTable[] = [{name: "Brisbane",columns: [{type: "number",name: "Price",values: [100000, 200000, 300000],},],},{name: "Melbourne",columns: [{type: "number",name: "Price",values: [100000, 200000, 300000],},],},{name: "Sydney",columns: [{type: "number",name: "Price",values: [100000, 200000, 300000],},],},];export function App() {const [callback, setCallback] = React.useState<SelectDataTableRequest | undefined>();React.useEffect(() => {onSelectDataTable((options) => {setCallback(options);});}, []);function getDataForCity(name: string) {const table = DATA_TABLES.find((table) => table.name === name);if (!table) {throw new Error(`Can't find table with name: ${name}`);}if (!callback) {throw new Error(`onSelectDataTable callback is not defined`);}callback.selectDataTable(table);}return (<div><div>Choose a location</div><div><buttononClick={() => {getDataForCity("Brisbane");}}>Brisbane</button></div><div><buttononClick={() => {getDataForCity("Melbourne");}}>Melbourne</button></div><div><buttononClick={() => {getDataForCity("Sydney");}}>Sydney</button></div></div>);}
How to test data providers
If a provider renders a UI, the UI can be tested the same as any other app — by opening the app in the Developer Portal and clicking the Preview button.
If you want to test how a provider interacts with a consumer, the only option is to test it via Canva's Bulk Create feature. In the future, as other consumers are released, more options will become available.
Step 1: Select a data provider
- Create a design in Canva.
- In the object panel, click Apps.
- Select Bulk Create.
- Click More data sources.
- Select a provider.
Step 2: Generate a design with the data
- Add a text element to the design.
- Right-click the element.
- Select Assign data.
- In the dropdown that appears, select one or more columns from the data table.
- In the object panel, click Continue.
- Select one or more rows of data.
- Click Generate.
API reference
Code samples
Without UI
import React from "react";import { DataTable, onSelectDataTable } from "@canva/preview/data";const DATA_TABLE: DataTable = {name: "Dog breeds",columns: [{type: "string",name: "name",values: ["Golden retriever","Labrador retriever","Flat-coated retriever","Goldendoodle",],},{type: "string",name: "country",values: ["Scotland", "United Kingdom", "England", "Australia"],},{ type: "number", name: "weight", values: [35, 35, 30, 25] },{type: "boolean",name: "isPureBreed",values: [true, true, true, false],},],};export function App() {React.useEffect(() => {onSelectDataTable((options) => {options.selectDataTable(DATA_TABLE);});}, []);}
With UI
import React from "react";import {DataTable,SelectDataTableRequest,onSelectDataTable,} from "@canva/preview/data";const DATA_TABLES: DataTable[] = [{name: "Brisbane",columns: [{type: "number",name: "Price",values: [100000, 200000, 300000],},],},{name: "Melbourne",columns: [{type: "number",name: "Price",values: [100000, 200000, 300000],},],},{name: "Sydney",columns: [{type: "number",name: "Price",values: [100000, 200000, 300000],},],},];export function App() {const [callback, setCallback] = React.useState<SelectDataTableRequest | undefined>();React.useEffect(() => {onSelectDataTable((options) => {setCallback(options);});}, []);function getDataForCity(name: string) {const table = DATA_TABLES.find((table) => table.name === name);if (!table) {throw new Error(`Can't find table with name: ${name}`);}if (!callback) {throw new Error(`onSelectDataTable callback is not defined`);}callback.selectDataTable(table);}return (<div><div>Choose a location</div><div><buttononClick={() => {getDataForCity("Brisbane");}}>Brisbane</button></div><div><buttononClick={() => {getDataForCity("Melbourne");}}>Melbourne</button></div><div><buttononClick={() => {getDataForCity("Sydney");}}>Sydney</button></div></div>);}