Connect Canvas to front end

Learn to incorporate a Canvas composition into your front-end application.

info

The code below expects a published version of the composition be available. If the composition is only available in "preview" state, Uniform will return a null composition, which will result in errors.

For more information on composition state, see the glossary. The methods on the CanvasClient also support the ability to retrieve compositions in a specific state (for example, not "published," which is the default value).

  1. Click the Uniform logo at the top of the page to return to the Uniform team home page.

  2. Create an API key with the following custom permissions:

    Uniform Canvas > Compositions > Read Published

About this step

If you already have an API key with these permissions, you can skip this step.

  1. Add the following values to your .env file. You collected these values when you created the Uniform API key:

    Uniform valueEnvironment variable
    API KeyUNIFORM_API_KEY
    Project IDUNIFORM_PROJECT_ID

About this step

Technically you don't need to set these values in environment variables. You could hard-code the values into your app, but using environment variables is a "best practice."

The changes needed to the front-end depends on the technology used to build the front-end.

To make these instructions easier to follow, a specific example is used. The example activates Canvas for the following page, where the presentation logic in the <main> tag will be controlled by a user with Canvas:

import Head from "next/head"; export async function getStaticProps() { return { props: { title: "Sample app", message: "Hello", }, }; } export default function Home({ title, message }) { return ( <div> <Head> <title>{title}</title> </Head> <main> <h1>{message}</h1> </main> </div> ); }

tip

This section guides you through the process of activating Canvas by explaining each step. It takes longer to go through, but it will help you understand why each line of code is needed.

  1. Add the following packages to your app:

    @uniformdev/canvas @uniformdev/canvas-react
  2. Create your first Next.js page index.jsx and import CanvasClient:

    import Head from 'next/head' import { CanvasClient, } from '@uniformdev/canvas' ...
  3. Update server static props, while adding CanvasClient:

    export async function getStaticProps() { const client = new CanvasClient({ apiKey: process.env.UNIFORM_API_KEY, projectId: process.env.UNIFORM_PROJECT_ID, }); return { props: { title: "Sample app", message: "Hello", }, }; }
  4. Fetch composition data for the home page slug: '/':

    export async function getStaticProps() { const client = new CanvasClient({ apiKey: process.env.UNIFORM_API_KEY, projectId: process.env.UNIFORM_PROJECT_ID, }); const { composition } = await client.getCompositionBySlug({ slug: "/", }); return { props: { title: "Sample app", message: "Hello", }, }; }
  5. Pass the whole composition data object to the props:

    export async function getStaticProps() { const client = new CanvasClient({ apiKey: process.env.UNIFORM_API_KEY, projectId: process.env.UNIFORM_PROJECT_ID, }); const { composition } = await client.getCompositionBySlug({ slug: "/", }); return { props: { title: "Sample app", message: "Hello", composition, }, }; }
  6. Import UniformComposition component:

    import Head from 'next/head' import { CanvasClient, } from '@uniformdev/canvas' import { UniformComposition, } from '@uniformdev/canvas-react'; ...
  7. Wrap your markup with UniformComposition component and pass composition prop in it:

    export default function Home({ title, message, composition }) { return ( <UniformComposition data={composition}> <div> <Head> <title>{title}</title> </Head> <main> <h1>{message}</h1> </main> </div> </UniformComposition> ); }
  8. Import UniformSlot and replace your content with just this slot:

    import { UniformComposition, UniformSlot, } from '@uniformdev/canvas-react'; ... export default function Home({ title, message, composition }) { return ( <UniformComposition data={composition}> <div> <Head> <title>{title}</title> </Head> <main> <UniformSlot name="body" /> </main> </div> </UniformComposition> ); }

About this step

You add the UniformSlot component in the places that match where you defined slots in your composition component.

To make these instructions easier to follow, a specific example is used. The example activates Canvas for the following page, where the presentation logic in the <main> tag will be controlled by a user with Canvas:

<script lang="ts" setup> const title = 'Sample App'; const message = 'Hello'; </script> <template> <div> <Head> <Title>{{ title }}</Title> </Head> <main> <h1>{{ message }}</h1> </main> </div> </template>

tip

This section guides you through the process of activating Canvas by explaining each step. It takes longer to go through, but it will help you understand why each line of code is needed.

  1. Add the following packages to your app:

    @uniformdev/canvas @uniformdev/context @uniformdev/canvas-vue @uniformdev/context-vue @uniformdev/uniform-nuxt
  2. Add the Nuxt module to nuxt.config.ts:

    export default defineNuxtConfig({ modules: ["@uniformdev/uniform-nuxt"], uniform: { projectId: process.env.UNIFORM_PROJECT_ID, readOnlyApiKey: process.env.UNIFORM_API_KEY, }, });
  3. Update the page's script to use useUniformComposition (it's auto imported by the module):

    <script lang="ts" setup> const title = "Sample App"; const { composition } = await useUniformComposition({ slug: "/" }); </script>
  4. Update the template to use <UniformComposition> and <UniformSlot> to render the composition (they're both auto imported by the module):

    <template> <UniformComposition :data="composition"> <div> <Head> <Title>{{ title }}</Title> </Head> <main> <UniformSlot name="body" /> </main> </div> </UniformComposition> </template>
  5. Now you should tell <UniformComposition> how to render each Uniform component. To do so, use the generic component renderer DefaultNotImplementedComponent, but you can update the resolveRenderer function to use any Vue components you want based on the Uniform component type.

    <script lang="ts" setup> import { DefaultNotImplementedComponent } from '@uniformdev/canvas-vue'; const resolveRenderer = ({ type }) => { // TODO: extend the function to return a component based on the `type` property. return DefaultNotImplementedComponent; }; const title = 'Sample App'; const { composition } = await useUniformComposition({ slug: '/' }); </script> <template> <UniformComposition :data="composition" :resolve-renderer="resolveRenderer"> <div> <Head> <Title>{{ title }}</Title> </Head> <main> <Slot name="body" /> </main> </div> </UniformComposition> </template>