packages/docs/elements/submit-an-element.mdx
Have a small, remixable Remotion Element? We'd like to see it.
Follow this checklist from top to bottom when preparing an Element.
A strong Element can be previewed, copied into a Remotion project, and used as a video building block.
Good Elements are:
If two variants are worth showing, make two separate Element pages instead of adding a variant prop.
Start from the reusable template in packages/docs/elements-template/.
Add:
packages/docs/elements/<category>/<slug>/index.mdx pageFor example:
export const MyElement = () => {
return <div style={{width: '100%', height: '100%'}}>...</div>;
};
The source file should work when dragged or copied into a project.
To give an Element a fixed size, set elementWidth and elementHeight on the ElementPage in index.mdx:
<ElementPage
component={MyElement}
elementWidth={900}
elementHeight={260}
>
Then make the Element fill that area in its source file:
import {AbsoluteFill} from 'remotion';
export const MyElement = () => {
return <AbsoluteFill>...</AbsoluteFill>;
};
Size the Element to the smallest useful bounding box.
Use previewPadding on the ElementPage if the docs preview needs more breathing room without changing the Element's drag dimensions or adding source padding.
Do not put the wrapper <Sequence> into the Element source file.
Let the Studio-inserted <Sequence> handle placement in the video.
Don't use left, right, top, and bottom, etc. to position your element.
Inner Element styles can animate entrance values such as translate, scale, and opacity.
For animation, keep the timing inside the component but let the surrounding project decide how long the Element appears:
import {Interactive, interpolate, useCurrentFrame} from 'remotion';
export const AnimatedElement = () => {
const frame = useCurrentFrame();
return (
<Interactive.Div
name="Container"
style={{
width: '100%',
height: '100%',
opacity: interpolate(frame, [0, 20], [0, 1]),
translate: interpolate(frame, [0, 20], ['0px 40px', '0px 0px']),
}}
>
Hello
</Interactive.Div>
);
};
Only add Interactive.* wrappers when they expose useful Studio controls.
Every Interactive.* wrapper should have a descriptive name.
Avoid:
Interactive.* wrappers that represent the same visual objectdisplayNameFor the main inner editable element, use a generic name such as Container.
You should follow Interactivity best practices.
For a single editable object, use one named wrapper:
import {Interactive, interpolate, useCurrentFrame} from 'remotion';
export const Badge = () => {
const frame = useCurrentFrame();
return (
<Interactive.Div
name="Container"
style={{
opacity: interpolate(frame, [0, 20], [0, 1]),
translate: interpolate(frame, [0, 20], ['0px 24px', '0px 0px']),
padding: 24,
borderRadius: 16,
backgroundColor: 'white',
}}
>
Launch day
</Interactive.Div>
);
};
If a child has separate useful controls, make the child interactive and name it:
import {Interactive} from 'remotion';
export const Badge = () => {
return (
<Interactive.Div
name="Container"
style={{
padding: 24,
borderRadius: 16,
backgroundColor: 'white',
}}
>
<Interactive.Div
name="Title"
style={{
color: 'black',
fontSize: 44,
fontWeight: 700,
}}
>
Launch day
</Interactive.Div>
</Interactive.Div>
);
};
When submitting an Element as a pull request, include: