Examples
App elements
Assets and media
Fundamentals
Intents
Design interaction
Drag and drop
Design elements
Localization
Content replacement
Feature support
Feature detection and conditional functionality based on platform support.
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 feature_supportSHELL -
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 { addElementAtPoint, addPage } from "@canva/design";import { useState } from "react";import * as styles from "styles/components.css";import { useFeatureSupport } from "utils/use_feature_support";import { HomePage } from "./home";import { InteractionPage } from "./interaction";type AppPage = "home" | "interaction";/*** Top-level component that manages state across the example app.**/export const App = () => {const [appPage, setAppPage] = useState<AppPage>("home");// A new callback is returned each time the feature support profile of the// current page changes in Canva.const isSupported = useFeatureSupport();// Check whether `addElementAtPoint` and `addPage` are supported in the current page.const isInteractionSupported = isSupported(addElementAtPoint, addPage);const renderPage = (page: AppPage) => {switch (page) {case "home":return (<HomePage enterInteractionPage={() => setAppPage("interaction")} />);break;case "interaction":return (<InteractionPagegoBack={() => setAppPage("home")}isInteractionSupported={isInteractionSupported}/>);default:return;}};return <div className={styles.scrollContainer}>{renderPage(appPage)}</div>;};
TYPESCRIPT
import { Button, Rows, Text, Title } from "@canva/app-ui-kit";type HomePageProps = {enterInteractionPage: () => void;};/*** Home Page component containing page controls**/export const HomePage = (props: HomePageProps) => {return (<Rows spacing="1.5u"><Title>Home page</Title><Text>This example app demonstrates how to toggle interactive UI based on thecurrently available features.</Text><Button variant="primary" onClick={props.enterInteractionPage}>Enter interactions page</Button></Rows>);};
TYPESCRIPT
import { AppUiProvider } from "@canva/app-ui-kit";import { createRoot } from "react-dom/client";import { App } from "./app";import "@canva/app-ui-kit/styles.css";const root = createRoot(document.getElementById("root") as Element);function render() {root.render(<AppUiProvider><App /></AppUiProvider>,);}render();if (module.hot) {module.hot.accept("./app", render);}
TYPESCRIPT
import { Alert, Button, Rows } from "@canva/app-ui-kit";import { addElementAtPoint, addPage } from "@canva/design";type InteractionPageProps = {goBack: () => void;isInteractionSupported: boolean;};/*** A page component containing various buttons to interact with the design.**/export const InteractionPage = (props: InteractionPageProps) => {return (<Rows spacing="1.5u">{!props.isInteractionSupported && <UnsupportedAlert />}<Button variant="primary" onClick={props.goBack}>Back</Button><Buttondisabled={!props.isInteractionSupported}variant="secondary"onClick={() => addElementAtPoint({ type: "shape", ...shape })}>Add a shape at a point</Button><Buttondisabled={!props.isInteractionSupported}variant="secondary"onClick={() =>addElementAtPoint({type: "group",children: [{type: "shape",...shape,left: 0,top: 0,width: 200,height: "auto",},{type: "embed",url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",left: 300,top: 100,width: 200,height: "auto",},],})}>Add a group at a point</Button><Buttondisabled={!props.isInteractionSupported}variant="secondary"onClick={() => addPage()}>Add a new page</Button></Rows>);};const shape = {paths: [{d: "M 0 0 H 100 V 100 H 0 L 0 0",fill: {dropTarget: false,color: "#ff0099",},},],viewBox: {width: 100,height: 100,top: 0,left: 0,},};const UnsupportedAlert = () => (<Alert tone="warn" title="Shapes, Groups and Pages can't be added to Docs.">Try using this app in a different design type.</Alert>);
TYPESCRIPT
# Feature supportDemonstrates how to detect and handle feature availability across different design types and contexts. Shows dynamic feature detection, graceful degradation, and context-aware UI rendering.For API reference docs and instructions on running this example, see: https://www.canva.dev/docs/apps/examples/feature-support/.Related examples: This pattern should be used across all apps to ensure proper functionality across different design contexts.NOTE: This example differs from what is expected for public apps to pass a Canva review:- Feature detection patterns are simplified for demonstration purposes only. Production apps must implement feature detection for all functionality that depends on design context or user permissions- Error handling is simplified for demonstration. Production apps must implement comprehensive error handling with clear user feedback and graceful failure modes- 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)