Positioning elements

How to arrange elements in a user's design.

By default, adding an element to the user's design positions the element in the center of the page and scales it to a size that's determined by Canva.

Likewise, elements inside groups and app elements have default positions and scaling.

Apps can, however, override these values to set the position of elements in either context.

Check out the Layout design guidelines

Our design guidelines help you create a high-quality app that easily passes app review.

The syntax for positioning an element depends on the method that renders the element.

When calling the addNativeElement method, pass the position in with the first argument:

await addNativeElement({
type: "EMBED",
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
// Position
width: 640,
height: 360,
top: 0,
left: 0,
rotation: 0,
});
ts

When calling the addOrUpdateElement method, pass the position in as the second argument:

appElement.addOrUpdateElement(
{
// app element data goes here
},
{
// Position
width: 640,
height: 360,
top: 0,
left: 0,
rotation: 0,
}
);
ts

In both cases, the following properties must be used together:

  • width
  • height
  • top
  • left

The rotation property is always optional, but only has an effect if the positional properties are set.

  1. In the Developer Portal, enable the canva:design:content:read permission. In the future, the Apps SDK will throw an error if the required permissions are not enabled. To learn more, see Configuring permissions.

  2. Call the the getCurrentPageContext method:

    import { getCurrentPageContext } from "@canva/design";
    const context = await getCurrentPageContext();
    console.log(context.dimensions); // => { width: 1280, height: 720 }
    ts

    The method returns a dimensions property that you can use to:

    • Position elements within the bounds of the current page.
    • Position elements in relative terms — for example, in the bottom-right corner.

You can set the position of elements inside groups and app elements, and since app elements are essentially groups with extra features, the approach to positioning elements is the same.

You can think of an app element and a group as a box.

By default, the box doesn't have a width or height. Instead, the size of the box is based on the size and spacing between the elements it contains.

The elements inside a box must have a width and a height. (The one exception is text elements, which can't have a predefined height.)

When the width is defined as a number, the height can be set to "auto" (and vice versa). At runtime, Canva replaces "auto" with a value that maintains the aspect ratio of the element.

Within a box, elements can be positioned with top and left coordinates. These coordinates are relative to the box's origin — that is, the top-left corner of the box.

The origin is determined by the box's topmost and leftmost elements. For example, if the topmost element has a top position of 50 and the leftmost element has a left position of 100, then:

  • The top and left coordinates of the box start from 50 and 100
  • The top and left coordinates of all other elements are relative to 50 and 100

To illustrate, here's a diagram:

This can be confusing — especially if you're using negative values for positions — so we recommend treating the top and left coordinates as 0 and 0, even though this isn't strictly required.

Elements can be positioned to overlap or to have spacing between them. The size of the box grows or shrinks to accommodate for the combined size of the elements.

When elements overlap, the ordering of the elements is determined by the order in which the elements are rendered. The elements later in an array are rendered in front of elements earlier in the array.

Boxes do not have padding. There's always one element positioned against each edge of the box.

Within a box, dimensions and coordinates are defined with relative units, not absolute units. This means 200 is always twice as large as 100, but these numbers don't correspond to pixel values.

The end result is that, if a design is 1920 pixels × 1280 pixels, setting the dimensions of a box's elements to a combined size of 1920 pixels × 1280 pixels will not necessarily result in the box extending to the edges of the design. Instead, the box will be scaled to a size that's calculated by Canva.

How Canva determines the absolute size of elements depends on a variety of factors that may change over time and is beyond the scope of this documentation.

The key takeaway is to never treat dimensions or coordinates within a box as absolute values.

import React from "react";
import { getCurrentPageContext, initAppElement } from "@canva/design";
const appElement = initAppElement({
render: () => {
return [
{
type: "EMBED",
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
width: 640,
height: 360,
top: 0,
left: 0,
},
];
},
});
export function App() {
async function handleClick() {
const context = await getCurrentPageContext();
if (!context.dimensions) {
console.warn("The current design does not have dimensions");
return;
}
const width = 640;
const height = 360;
const top = context.dimensions.height - height;
const left = context.dimensions.width - width;
await appElement.addOrUpdateElement(
{
// app element data goes here
},
{
width,
height,
top,
left,
}
);
}
return (
<div>
<button onClick={handleClick}>Create positioned app element</button>
</div>
);
}
tsx
import React from "react";
import { addNativeElement, getCurrentPageContext } from "@canva/design";
export function App() {
async function handleClick() {
const context = await getCurrentPageContext();
if (!context.dimensions) {
console.warn("The current design does not have dimensions");
return;
}
const width = 640;
const height = 360;
const top = context.dimensions.height - height;
const left = context.dimensions.width - width;
await addNativeElement({
type: "EMBED",
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
width,
height,
top,
left,
});
}
return (
<div>
<button onClick={handleClick}>Create positioned native element</button>
</div>
);
}
tsx
import React from "react";
import { addNativeElement } from "@canva/design";
export function App() {
async function handleClick() {
await addNativeElement({
type: "GROUP",
children: [
{
type: "EMBED",
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
width: 100,
height: 100,
top: 0,
left: 0,
},
{
type: "EMBED",
url: "https://www.youtube.com/watch?v=o-YBDTqX_ZU",
width: 100,
height: 100,
top: 0,
left: 100,
},
],
});
}
return (
<div>
<button onClick={handleClick}>Add group element</button>
</div>
);
}
tsx