Skip to main content

Interactivity best practices

Write editable Remotion components so the Studio interactivity can understand the values that should be changed visually.

When a value is shown as computed in the Studio, it often means that the value is hidden behind a variable, helper function, conditional expression or transform string.

Use Interactive.* for tweakable elements

Use the Interactive namespace when an HTML or SVG element should be selected, moved or edited in the Studio.

Interactive elements
// 👍 Selectable and editable in the Studio <Interactive.Div style={{fontSize: 80, padding: 24}}>Hello</Interactive.Div> // 👎 A regular element is not Studio-editable <div style={{fontSize: 80, padding: 24}}>Hello</div>

For a custom component, see Make a component interactive.

Prompt
/remotion-best-practices Make this element editable in Remotion Studio. Use Interactive.* for tweakable HTML/SVG elements and keep editable style values inline.

Keep editable values visible

Put values that should be edited in the Studio directly into the JSX. This applies to static style values, keyframes, easing and transform props.

Inline values
// 👍 Inline values can be standardized and keyframed <Interactive.Div style={{ color: 'white', fontSize: 80, scale: interpolate(frame, [0, 30], [0, 1], { easing: Easing.spring({damping: 200}), }), rotate: interpolate(frame, [0, 30], ['0deg', '20deg']), translate: interpolate(frame, [0, 30], ['0px 0px', '0px 120px']), }} /> // 👎 Values hidden behind variables, helpers or strings become computed const container: React.CSSProperties = { color: 'white', fontSize: 80, }; const translateY = interpolate(frame, [0, 30], [0, 120]); const rotation = interpolate(frame, [0, 30], [0, 20]); <Interactive.Div style={{ ...container, transform: `translateY(${translateY}px) rotate(${rotation}deg)`, }} />

Use standalone spring() only when the animation needs a frame-driven physical spring simulation. Use individual CSS transform properties such as scale, rotate and translate instead of composing a transform string.

Prompt
/remotion-best-practices Fix computed values in Remotion Studio. Follow https://www.remotion.dev/docs/studio/interactivity-best-practices#keep-editable-values-visible. Move editable values into the JSX style object, keep interpolate() keyframes inline, use Easing.spring() as easing, and replace transform strings with scale/rotate/translate.

Keep composition metadata inline

When scaffolding a composition, keep the component and its <Composition> registration in the same file. Keep static width, height, fps, durationInFrames and defaultProps inline.

The Props editor can save visual edits back to your code when defaultProps is an inline object literal on <Composition> or <Still>. If the Studio shows `defaultProps` prop must be a hardcoded value in the <Composition/> tag, move the values into the JSX.

Composition metadata
// 👍 Static metadata and defaults are inline and nearby <Composition id="my-video" component={MyComponent} durationInFrames={150} fps={30} width={1920} height={1080} defaultProps={{title: 'Hello', color: '#0b84ff'}} /> // 👎 Static metadata is hidden behind helpers or variables const defaultProps = {title: 'Hello', color: '#0b84ff'}; const calculateMetadata = () => { return {durationInFrames: 150, fps: 30, width: 1920, height: 1080}; }; <Composition id="my-video" component={MyComponent} calculateMetadata={calculateMetadata} defaultProps={{ title: 'Hello', }} />

Use calculateMetadata() when metadata depends on dynamic input props, fetched data or asset metadata.

Prompt
/remotion-best-practices Fix Composition metadata for Remotion Studio. Keep defaultProps, width, height, fps, and durationInFrames inline on the Composition unless calculateMetadata needs dynamic data.

Keep effects editable

Keep editable effect parameters inline in the effect call and keep the effect array shape unconditional.

Effects
// 👍 Parameters are inline and the array shape is stable <CanvasImage src={src} width={1280} height={720} effects={[ radialProgressiveBlur({ center: [0.5, 0.5], point1: [0.86, 0.36], point2: [0.68, 0.84], }), ]} /> // 👎 Values are hidden and the effect only exists conditionally const center = [0.5, 0.5] as const; <CanvasImage src={src} width={1280} height={720} effects={enabled ? [ radialProgressiveBlur({ center, }), ] : []} />

Render separate elements if one version should have effects and another should not.

Prompt
/remotion-best-practices Fix computed effect controls in Remotion Studio. Keep effect parameters inline in the effect call and keep the effects array shape unconditional.

See also