# Rendering in Uniform

> Learn how to render components and compositions that are defined using Uniform Canvas in your front-end application.

Source: https://docs.uniform.app/docs/guides/composition/rendering

In this section, you learn how to render components and compositions that are defined using Uniform Canvas in your front-end application.

This usually involves these steps:

1. Initial project setup for Uniform

   - [Create API key](#create-api-key)
2. Render compositions and slots

- [Fetch composition data](#fetch-composition-data)
- [Render composition](#render-composition)

  - [Next.js](#nextjs)
  - [Nuxt 3](#nuxt-3)
- [Render slots](#render-slots)

## Create API key

1. Click the Uniform logo at the top of the page to return to the Uniform team home page.
2. In the **Security** section, click **API keys**.
3. [Create an API key](https://docs.uniform.app/docs/guides/apis#create-api-key) with a role that includes the following permission:

   ```
   Uniform Canvas > Compositions > Read Published
   ```

   > **Note:**
   >
   > The built-in **Viewer** role includes this permission. Alternatively, you can [create a custom role](https://docs.uniform.app/docs/guides/roles-and-permissions) with this specific permission. If you already have an API key with these permissions, you can skip this step.
4. Add the following values to your `.env` file. You collected
   these values when you created the Uniform API key:

   | Uniform value | Environment variable |
   | --- | --- |
   | API Key | `UNIFORM_API_KEY` |
   | Project ID | `UNIFORM_PROJECT_ID` |

## Fetch composition data

Most modern front-end frameworks like Next.js and Nuxt 3 provide dynamic routing capabilities that are ideal for rendering compositions.

By leveraging dynamic routes, you can create a single file such as `/pages/[...path].jsx` that handles composition rendering for any URL path. This pattern provides a clean and maintainable way to serve compositions across your entire application.

It also empowers content editors to independently manage the site structure through [project maps](https://docs.uniform.app/docs/guides/project-maps) in Uniform. Editors can create, modify, and reorganize pages without requiring developer assistance for sitemap changes.

When rendering a composition you will need to resolve the current URL to fetch the corresponding composition data.

Refer to the [routing guide](https://docs.uniform.app/docs/guides/composition/url-management/routing/) for more information on how to implement routing using Uniform.

- [Routing](https://docs.uniform.app/docs/guides/composition/url-management/routing): Learn about routing approaches with Uniform.
- [Routing with Next.js](https://docs.uniform.app/docs/guides/composition/url-management/routing/nextjs-helper-methods): Helper methods to simplify routing with Uniform in Next.js.

## Render composition

### Next.js

To make these instructions easier to follow, a specific example is used.

The example activates Canvas for the following dynamic Next.js page (using the page router and server-side rendering), where the content of the `<main>` tag will be rendered with Canvas:

`/pages/[...path].jsx`

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

1. Add the following packages to your app:

   ```
   @uniformdev/canvas
   @uniformdev/canvas-react
   @uniformdev/canvas-next
   ```
2. Render the page with the composition data:

   **Next.js (complete)**

   1. Add the following code which fetches the composition data for the current route using the Uniform Route API and passes the data to the page component as `data` prop which is then passed to the `UniformComposition` component.

      `/pages/[...path].jsx`

      ```jsx
      import Head from "next/head";
      import { withUniformGetServerSideProps } from "@uniformdev/canvas-next/route";
      import { UniformComposition, UniformSlot } from "@uniformdev/canvas-react";

      // this example is using server-side rendering (SSR) for simplicity
      export const getServerSideProps = withUniformGetServerSideProps({
        handleComposition: async ({ compositionApiResponse }) => {
          const { composition } = compositionApiResponse || {};
          return {
            props: {
              title: "Sample app",
              data: composition
            },
          };
        },
      });

      export default function Page({title, data: composition }) {
        return (
          <UniformComposition data={composition}>
            <div>
              <Head>
                <title>{title}</title>
              </Head>
              <main>
                <UniformSlot name="body" />
              </main>
            </div>
          </UniformComposition>
        );
      }
      ```

   **Next.js (steps)**

   > **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. Replace the `getServerSideProps` function with the Uniform helper function.

      This function is using the Uniform Route API to fetch the composition data for the current route.

   `/pages/[...path].jsx`

   ```jsx
     import Head from 'next/head'
     import { withUniformGetServerSideProps } from "@uniformdev/canvas-next/route";
     
     // this example is using server-side rendering (SSR) for simplicity
     export const getServerSideProps = withUniformGetServerSideProps();
     // remaining code
     ...
   ```

   1. Configure the `getServerSideProps` function by defining the `handleComposition` callback which handles how the incoming composition data is passed to the page component.

   `/pages/[...path].jsx`

   ```jsx
     import Head from 'next/head'
     import { withUniformGetServerSideProps } from "@uniformdev/canvas-next/route";
     
     // this example is using server-side rendering (SSR) for simplicity
     export const getServerSideProps = withUniformGetServerSideProps({
       handleComposition: async ({ compositionApiResponse }) => {
         const { composition } = compositionApiResponse || {};
         return {
           props: {
             title: "Sample app",
             data: composition
           },
         };
       },
     });
     // remaining code
     ...
   ```

   2. Import `UniformComposition` component:

   `/pages/[...path].jsx`

   ```jsx
   import Head from 'next/head'
   import { withUniformGetServerSideProps } from "@uniformdev/canvas-next/route";
   import { UniformComposition } from '@uniformdev/canvas-react';
   ...
   ```

   3. Wrap your markup with `UniformComposition` component and pass `composition` prop to it:

   `/pages/[...path].jsx`

   ```jsx
   export default function Page({ title, data: composition }) {
     return (
       <UniformComposition data={composition}>
         <div>
           <Head>
             <title>{title}</title>
           </Head>
           <main>
             <h1>{message}</h1>
           </main>
         </div>
       </UniformComposition>
     );
   }
   ```

   4. Import `UniformSlot` and replace your content with just this slot:

   ```jsx
   // other imports
   ...
   import { UniformComposition, UniformSlot } from "@uniformdev/canvas-react";

   ...

   export default function Page({title, data: composition }) {
       return (
         <UniformComposition data={composition}>
           <div>
             <Head>
               <title>{title}</title>
             </Head>
             <main>
               <UniformSlot name="body" />
             </main>
           </div>
         </UniformComposition>
       );
     }
   ```

#### Starters and tutorials for Next.js

- [Next.js Starter: App Router](https://github.com/uniformdev/examples/tree/main/examples/nextjs-app-router): Check out the Next.js Starter for App Router on GitHub for a complete example.
- [Next.js Starter: Page Router](https://github.com/uniformdev/examples/tree/main/examples/nextjs-starter): Check out the Next.js Starter for Page Router on GitHub for a complete example.
- [Next.js tutorial: App Router](https://docs.uniform.app/docs/learn/tutorials/nextjs-app-router): A step-by-step tutorial on how to build a Next.js app with App Router with Canvas.
- [Next.js tutorial: Page Router](https://docs.uniform.app/docs/learn/tutorials/nextjs): A step-by-step tutorial on how to build a Next.js app with Page Router with Canvas.

### Nuxt 3

To make these instructions easier to follow, a specific
example is used. The example activates Canvas for the following
dynamic page, where the content of the `<main>` tag will be
rendered with Canvas:

`/pages/[...path].vue`

```html
<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>

```

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`:

   `nuxt.config.ts`

   ```ts
   export default defineNuxtConfig({
     modules: ["@uniformdev/uniform-nuxt"],
     uniform: {
       projectId: process.env.UNIFORM_PROJECT_ID,
       readOnlyApiKey: process.env.UNIFORM_API_KEY,
     },
   });
   ```
3. Render the page with the composition data:

   **Nuxt 3 (complete)**

   Update the page component in `/pages/[...path].vue`:

   `/pages/[...path].vue`

   ```html
   <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';
   // get the path from the route
   const route = useRoute();
   const path = Array.isArray(route.params.path)
     ? `/${route.params.path.join("/")}`
     : `/${route.params.path}`;
   // fetch the composition
   const { composition, error } = await useUniformComposition({
     projectMapNodePath: path,
     });
     // handle any errors
     if (error?.value) {
       console.error("Error fetching composition from Uniform", error.value);
     }
   </script>
   <template>
     <UniformComposition :data="composition" :resolve-renderer="resolveRenderer">
       <div>
         <Head>
           <Title>{{ title }}</Title>
         </Head>
         <main>
           <UniformSlot name="body" />
         </main>
       </div>
     </UniformComposition>
   </template>
   ```

   **Nuxt 3 (steps)**

   > **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. Update the page's script to use the `useRoute` and `useUniformComposition` helper functions (they're auto imported by the module):

   `/pages/[...path].vue`

   ```html
   <script lang="ts" setup>
     const title = "Sample App";
     // get the path from the route
     const route = useRoute();
     const path = Array.isArray(route.params.path)
       ? `/${route.params.path.join("/")}`
       : `/${route.params.path}`;
     // fetch the composition
     const { composition, error } = await useUniformComposition({
       projectMapNodePath: path,
     });
     // handle any errors
     if (error?.value) {
       console.error("Error fetching composition from Uniform", error.value);
     }
   </script>
   ```

   2. Update the template to use `<UniformComposition>` and `<UniformSlot>` to render the composition (they're both auto imported by the module):

      `/pages/[...path].vue`

      ```html
        <template>
          <UniformComposition :data="composition">
            <div>
              <Head>
                <Title>{{ title }}</Title>
              </Head>
              <main>
                <UniformSlot name="body" />
              </main>
            </div>
          </UniformComposition>
        </template>
      ```
   3. 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.

      `/pages/[...path].vue`

      ```html
        <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';
        // get the path from the route
        const route = useRoute();
        const path = Array.isArray(route.params.path)
          ? `/${route.params.path.join("/")}`
          : `/${route.params.path}`;
        // fetch the composition
        const { composition, error } = await useUniformComposition({
          projectMapNodePath: path,
          });
          // handle any errors
          if (error?.value) {
            console.error("Error fetching composition from Uniform", error.value);
          }
        </script>
        <template>
          <UniformComposition :data="composition" :resolve-renderer="resolveRenderer">
            <div>
              <Head>
                <Title>{{ title }}</Title>
              </Head>
              <main>
                <UniformSlot name="body" />
              </main>
            </div>
          </UniformComposition>
        </template>
      ```

#### Starters and tutorials for Nuxt 3

- [Nuxt 3 Starter](https://github.com/uniformdev/examples/tree/main/examples/nuxtjs-starter): Check out the Nuxt 3 Starter on GitHub for a complete example.
- [Nuxt 3 tutorial](https://docs.uniform.app/docs/learn/tutorials/nuxt): A step-by-step tutorial on how to build a Nuxt 3 app with Canvas.

### Control rendered markup

During the composition rendering process, Uniform generates markup.
By default, the markup is surrounded by a `<div>` tag. This
tag can cause problems with certain forms of CSS.

This example demonstrates how to prevent this extra markup from being
generated.

**React**

```jsx
import Head from 'next/head'
import { UniformComposition, UniformSlot } from '@uniformdev/canvas-react'
function resolveRenderer(component) {
  ...
}
export default function Home({ composition }) {
  return (
    <UniformComposition data={composition} resolveRenderer={resolveRenderer} behaviorTracking="onLoad">
      <div>
        <Head>
          <title>Example</title>
        </Head>
        <main>
          <UniformSlot name='body' />
        </main>
      </div>
    </UniformComposition>
  )
}
```

## Render slots

When a Canvas component has slots, it's expected that the
components in the slot will be rendered in the front-end
application. Each Canvas component must be mapped to a
component type that's compatible with the front-end
technology used. You must provide the mapping for Uniform.

This example demonstrates how to define the mapping and
assign it to the component that controls the rendering
process.

### Using component registry

**React**

`HeroComponent.jsx`

```jsx
import { registerUniformComponent } from "@uniformdev/canvas-react";

export default function HeroComponent() {
  return <div>Hero Component Content</div>
}

registerUniformComponent({
  type: 'hero',
  component: HeroComponent,
});
```

As `<UniformSlot />` component doesn't import FE components directly,
we need to import them manually here to include them to the bundle
and run our `registerUniformComponent()`

```jsx
import './HeroComponent';
// Optionally you can override default fallback component - DefaultNotImplementedComponent
// Useful when your component mapping is not simple 1-to-1 relation
import { registerUniformComponent, NOT_IMPLEMENTED_COMPONENT } from "@uniformdev/canvas-react";
const MyNotImplementedComponent = (props) => {
  return (
    <div>COMPONENT {<code>{props.component.componentType}</code>} NOT IMPLEMENTED</div>
  );
}
registerUniformComponent({
  type: NOT_IMPLEMENTED_COMPONENT,
  component: MyNotImplementedComponent,
});
```

You still need to import canvasComponents.js to include all the components,
such as in NextJS `_app.js` is the best place for it.

```jsx
import '../components/canvasComponents';
```

### Using component resolver

_For the US region:_

**React**

```jsx
import Head from 'next/head'
import { CanvasClient } from '@uniformdev/canvas'
import { UniformComposition, UniformSlot, DefaultNotImplementedComponent } from '@uniformdev/canvas-react'
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: "Example page",
      composition,
    }
  }
}
function resolveRenderer({ type }) {
  const components = {
      // 'my_type': MyComponent,
  };
  return components[type] ?? DefaultNotImplementedComponent;
}
export default function Home({ title, composition }) {
  return (
    <UniformComposition data={composition} resolveRenderer={resolveRenderer}>
      <div>
        <Head>
          <title>{title}</title>
        </Head>
        <main>
          <UniformSlot name='body' />
        </main>
      </div>
    </UniformComposition>
  )
}
```

> **Info:**
>
> For more information, see the [UniformComposition](https://sdk.uniform.app/canvas-react) component reference.

_For the EU region:_

**React**

```jsx
import Head from 'next/head'
import { CanvasClient } from '@uniformdev/canvas'
import { UniformComposition, UniformSlot, DefaultNotImplementedComponent } from '@uniformdev/canvas-react'
export async function getStaticProps() {
  const client = new CanvasClient({
    apiHost: 'https://eu.uniform.app',
    edgeApiHost: 'https://eu.uniform.global',
    apiKey: process.env.UNIFORM_API_KEY,
    projectId: process.env.UNIFORM_PROJECT_ID,
  })
  const { composition } = await client.getCompositionBySlug({
    slug: "/",
  })
  return {
    props: { 
      title: "Example page",
      composition,
    }
  }
}
function resolveRenderer({ type }) {
  const components = {
      // 'my_type': MyComponent,
  };
  return components[type] ?? DefaultNotImplementedComponent;
}
export default function Home({ title, composition }) {
  return (
    <UniformComposition data={composition} resolveRenderer={resolveRenderer}>
      <div>
        <Head>
          <title>{title}</title>
        </Head>
        <main>
          <UniformSlot name='body' />
        </main>
      </div>
    </UniformComposition>
  )
}
```

> **Info:**
>
> For more information, see the [UniformComposition](https://sdk.uniform.app/canvas-react) component reference.

### Control rendered Uniform slot markup

A [slot](https://docs.uniform.app/docs/guides/models/components#slots) lets you define a list of child components to render inside a `<UniformSlot />` component.

By default, an array of children renders inside a minimal container (in case of React, it's `React.Fragment`).

`React`

```jsx
function Slide({ title, description, imageUrl }) {
  return (
    <div className="slide">
      <img src={imageUrl}/>
      <h4>{title}</h4>
      <p>{description}</p>
    </div>
  )
};

function Slider({ title }) {
  return (
    <div className="slider">
      <h3>{title}</h3>
      <div className="slides">
        <UniformSlot name='slides' />
      </div>
    </div>
  )
}
```

The final React output will look like this:

`React`

```jsx
<div class="slider">
  <h3>Slider title</h3>
  <div className="slides">
    <>
      <div class="slide">
        <img src="image-url-1"/>
        <h4>Slide 1</h4>
        <p>Slide 1 description</p>
      </div>
      <div class="slide">
        <img src="image-url-2"/>
        <h4>Slide 2</h4>
        <p>Slide 2 description</p>
      </div>
    </>
  </div>
</div>
```

Sometimes you may want to control how a slot renders its children. For example, the popular slider library [Swiper](https://swiperjs.com/react)
requires you to wrap slides with `<SwiperSlide />` component. Each slide should be the _immediate_ child of the parent `<Swiper />` component.
To achieve this in Uniform you can use the `wrapperComponent` prop of the `<UniformSlot />` component.

`React`

```jsx
import { Swiper, SwiperSlide } from 'swiper/react';

function Slide({ title, description, imageUrl }) {
  return (
    <>
      <img src={imageUrl}/>
      <h4>{title}</h4>
      <p>{description}</p>
    </>
  )
};

function SliderWrapperComponent({ items }) {
  return (
    <Swiper>
      {items.map((item, index) => (
        <SwiperSlide key={index}>
          {item}
        </SwiperSlide>
      ))}
    </Swiper>
  )
}

function Slider({ title }) {
  return (
    <div className="slider">
      <h3>{title}</h3>
      <div className="slides">
        <UniformSlot name='slides' wrapperComponent={SliderWrapperComponent} />
      </div>
    </div>
  )
}

```

> **Info:**
>
> For more information, see the [UniformComposition](https://sdk.uniform.app/canvas-react) component reference, and the guide for [routing with Next.js](https://docs.uniform.app/docs/guides/composition/url-management/routing/nextjs-helper-methods).
