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:example 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 "@canva/app-hooks";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 design context changes in Canva. This allows the app to react to// changes like switching between different design types (doc vs poster).const isSupported = useFeatureSupport();// Check whether `addElementAtPoint` and `addPage` are supported in the current design context.// These methods may not be available in certain design types like docs or whiteboards.const isInteractionSupported = isSupported(addElementAtPoint, addPage);const renderPage = (page: AppPage) => {switch (page) {case "home":return (<HomePage enterInteractionPage={() => setAppPage("interaction")} />);case "interaction":return (<InteractionPagegoBack={() => setAppPage("home")}isInteractionSupported={isInteractionSupported}/>);default:return;}};return <div className={styles.scrollContainer}>{renderPage(appPage)}</div>;};
TYPESCRIPT
// For usage information, see the README.md file.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
// 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
// For usage information, see the README.md file.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.* Demonstrates how to handle feature availability by disabling UI elements* and showing appropriate feedback when features aren't supported.**/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>);};// Simple shape configuration for demonstration purposes.// In production apps, this would typically be more dynamic or user-configurable.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 using the Canva Apps SDK's feature support system.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- The code structure is simplified: Production apps using [intents](https://www.canva.dev/docs/apps/intents/) are recommended to call the prepareDesignEditor function from src/intents/design_editor/index.tsx
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)