> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://contentful.com/developers/docs/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://contentful.com/_mcp/server. # Get started with the Experience Canvas Toolbar > Build an app for the Experience Canvas Toolbar location | Scaffold the experience-toolbar starter | Read canvas selection | Highlight nodes on the canvas This guide walks you through scaffolding, building, and running a minimal app for the [Experience Canvas Toolbar](/extensibility/app-framework/experience-canvas-toolbar-overview) location. For the concepts behind this location (the shared editing context, and how node content and design properties are updated), see the [Experience Canvas Toolbar overview](/extensibility/app-framework/experience-canvas-toolbar-overview). For full method signatures, see [`sdk.experiences` in the App SDK reference](/extensibility/app-framework/experience-canvas-toolbar-sdk-reference#experiences). > **Note** > > The toolbar location is gated behind a feature flag during rollout. Some accounts may not yet be able to install apps to this location. ## Prerequisites ### Setup * The latest LTS version of [Node.js](https://nodejs.org/en/) installed on your machine. * Be logged in to your Contentful account and have a Contentful space. If you don't have an account, [sign up](https://www.contentful.com/sign-up/) for it. * A space with Experience Orchestration enabled, and at least one experience or fragment to access its canvas. ### Knowledge * Read and write JavaScript or TypeScript. * Be familiar with the [Experience Canvas Toolbar concepts](/extensibility/app-framework/experience-canvas-toolbar-overview) — in particular, the distinction between content (Data Assembly) and design properties. ## Create your project The Experience Canvas Toolbar ships as a starter example rather than a CLI-prompted blank template. Scaffold it with the [`create-contentful-app`](/extensibility/app-framework/create-contentful-app) CLI's `--example` flag: ```bash npx create-contentful-app experience-toolbar --example experience-toolbar ``` > **Info** > > Unlike the blank templates (`javascript`, `typescript`, `vue`, `vite-react`, `nextjs`), `--example ` pulls a ready-made starter from the [`examples` directory](https://github.com/contentful/apps/tree/master/examples) in the `contentful/apps` repository. The experience-toolbar example lives at `examples/experience-toolbar`. The example doesn't ship an `app-definition.json` manifest — the toolbar location isn't a target state you can preconfigure this way, so registering the location happens through the CLI scripts in the next step rather than a checkbox in the app definition form. ## Register and run the app 1. Navigate into the generated project: ```bash cd experience-toolbar ``` 2. Create an app definition and register the toolbar location: ```bash npm run create-app-definition ``` > **Info** > > This script wraps the same `create-app-definition` / `add-locations` flow described in the example's own README — read it for the full set of prompts. 3. Start the local development server: ```bash npm start ``` 4. When you're ready to install the app to a space, build, upload, and activate it: ```bash npm run build npm run upload npm run activate ``` > **Info** > > For the general app definition and installation flow shared by all locations, see [Create a custom app](/extensibility/app-framework/tutorial). ## Read the canvas selection Once installed, open an experience or fragment in the editor with your app assigned to the toolbar location. The toolbar can read what's currently selected on the canvas through the [Selection API](/extensibility/app-framework/experience-canvas-toolbar-sdk-reference#selection-api): #### JavaScript ```js import { useSDK } from '@contentful/react-apps-toolkit'; import { useEffect, useState } from 'react'; const Toolbar = () => { const sdk = useSDK(); const [selection, setSelection] = useState(sdk.experiences.experience.selection.get()); useEffect(() => { return sdk.experiences.experience.selection.onChange(setSelection); }, [sdk]); const selectedNode = selection.nodeId ? sdk.experiences.experience.getNode(selection.nodeId) : null; return
{selectedNode ? selectedNode.id : 'Nothing selected'}
; }; export default Toolbar; ``` #### TypeScript ```typescript import { ExperienceCanvasToolbarAppSDK } from '@contentful/app-sdk'; import { useSDK } from '@contentful/react-apps-toolkit'; import { useEffect, useState } from 'react'; const Toolbar = () => { const sdk = useSDK(); const [selection, setSelection] = useState(sdk.experiences.experience.selection.get()); useEffect(() => { return sdk.experiences.experience.selection.onChange(setSelection); }, [sdk]); const selectedNode = selection.nodeId ? sdk.experiences.experience.getNode(selection.nodeId) : null; return
{selectedNode ? selectedNode.id : 'Nothing selected'}
; }; export default Toolbar; ``` > **Info** > > Use `getNode(nodeId)` with a known node ID — such as the one returned by the selection — to look up a single node, or `getRootNodes()` to enumerate the tree from its top-level nodes when you don't have an ID up front. ## Highlight a node on the canvas The scaffolded example also includes a "Highlight on canvas" button that calls `selection.highlight(nodeId)` to flash and scroll a node into view — useful for apps that reference a node from outside the canvas and want to point the editor at it. ```js sdk.experiences.experience.selection.highlight(nodeId, { flash: true, scrollIntoView: true }); ``` Read `examples/experience-toolbar`'s source for the full implementation. ## How the toolbar talks to the editor Calls you make through `sdk.experiences.*` are delegated from the toolbar's `ToolbarWidgetRenderer` to the host editor through the `ToolbarEditorApiRegistry` — the editor registers its API with `useRegisterToolbarEditorApi`, and the toolbar widget's SDK calls resolve against whatever the editor currently has registered. You don't need to interact with the registry directly; it's what makes `sdk.experiences.context`, the Experience API, the Selection API, and Data Assembly work from inside the toolbar. ## Next steps * [Experience Canvas Toolbar overview](/extensibility/app-framework/experience-canvas-toolbar-overview) — the concepts behind the shared toolbar location and the content-vs-design split. * [`sdk.experiences` reference](/extensibility/app-framework/experience-canvas-toolbar-sdk-reference#experiences) — full method signatures for the Experience API, Selection API, and Data Assembly. > **Info** > > Cross-cutting APIs such as `AgentContext`, `navigator.openExperience`, and taxonomy-scoped `access.can` checks are out of scope for this guide — they're deferred to a future phase of the Experience Canvas Toolbar work. > Build an app for the Experience Canvas Toolbar location | Scaffold the experience-toolbar starter | Read canvas selection | Highlight nodes on the canvas