RVE LogoReact Video EditorDOCS
RVE SDK/Components/React Video Editor

React Video Editor

A modular, drop-in React video editor with sidebar panels, Remotion-powered player, renderer abstraction, autosave, theming, and pluggable media adaptors

The RVE Editor is a composable, drop-in editor shell that wires together the core building blocks of a video editing UI: a Remotion-powered player, a modular sidebar with overlay panels, timeline configuration, autosave hooks, theme management, and a renderer abstraction. You stay in control of data and backends via explicit props and adaptors.

Under the hood, RVE uses Remotion for rendering and playback, and exposes a renderer interface (e.g. HTTP/SSR or Lambda) so you can plug in your own backend. Media sourcing is handled by a flexible adaptor layer (e.g. Pexels), while overlays and timeline config remain app-controlled.

Editor vs Player-only

Use full Editor mode for an all-in-one editing UI (sidebar + editor + autosave). Switch to player-only mode when you just need an embeddable, fullscreen player with overlays and responsive sizing, for example on mobile or preview pages.

Key Features

  • Renderer abstraction: Bring your own backend via a simple VideoRenderer interface; ships with HttpRenderer.
  • Player-only mode: Fullscreen, responsive player without the editor UI for lightweight embeds.
  • Modular sidebar: Default sidebar with pluggable overlay panels; disable or replace with your own.
  • Autosave hooks: onSave callback delivers the full serialized EditorState on every save, plus visible autosave status.
  • Theming: Custom theme registry, default themes toggle, and external theme switching.
  • Media adaptors: Plug-in sources for video, images, audio, stickers, templates, and animations.
  • Timeline config: Control rows, zoom constraints, snapping behavior, and push-on-drag.
  • Responsive video sizing: Aspect ratio and explicit dimension controls for predictable layout.
  • Mobile-conscious: Player-only mode includes mobile viewport height handling.

Usage Example

Basic (Client-Side Rendering — Default)

import { ReactVideoEditor } from '@reactvideoeditor/react-video-editor/react-video-editor';
import '@reactvideoeditor/react-video-editor/styles.css';

export default function VideoEditorPage() {
  return (
    <div className="w-full h-screen">
      <ReactVideoEditor
        projectId="MyComposition"
        fps={30}
        disabledPanels={[]}
        defaultTheme="dark"
        showDefaultThemes={true}
      />
    </div>
  );
}

With Server Rendering (Optional)

import React from 'react';
import { HttpRenderer } from '@reactvideoeditor/react-video-editor/utils/http-renderer';
import { ReactVideoEditor } from '@reactvideoeditor/react-video-editor/react-video-editor';
import { createPexelsVideoAdaptor } from '@reactvideoeditor/react-video-editor/adaptors/pexels-video-adaptor';
import { createPexelsImageAdaptor } from '@reactvideoeditor/react-video-editor/adaptors/pexels-image-adaptor';
import '@reactvideoeditor/react-video-editor/styles.css';

export default function VideoEditorPage() {
  const PROJECT_ID = 'MyComposition';

  const availableThemes = [
    { id: 'rve', name: 'RVE', className: 'rve', color: '#3E8AF5' },
  ];

  const ssrRenderer = React.useMemo(
    () =>
      new HttpRenderer('/api/latest/ssr', {
        type: 'ssr',
        entryPoint: '/api/latest/ssr',
      }),
    []
  );

  return (
    <div className="w-full h-screen">
      <ReactVideoEditor
        projectId={PROJECT_ID}
        fps={30}
        customRenderer={ssrRenderer}
        enableWebRender={true}
        showRenderSettings={true}
        disabledPanels={[]}
        availableThemes={availableThemes}
        defaultTheme="dark"
        sidebarWidth="400px"
        sidebarIconWidth="57.6px"
        showIconTitles={false}
        adaptors={{
          video: [createPexelsVideoAdaptor('YOUR_PEXELS_API_KEY')],
          images: [createPexelsImageAdaptor('YOUR_PEXELS_API_KEY')],
        }}
        onThemeChange={(themeId) => console.log('Theme changed:', themeId)}
      />
    </div>
  );
}

Component Structure

ReactVideoEditor/
├── components/
│   ├── core/
│   │   ├── editor.tsx              # Main editor surface
│   │   └── video-player.tsx        # Remotion-based player
│   ├── shared/
│   │   └── default-sidebar.tsx     # Default sidebar with overlay panels
│   ├── autosave/
│   │   └── autosave-status.tsx     # Autosave UI indicator
│   ├── providers/
│   │   ├── react-video-editor-provider.tsx  # Top-level provider composition
│   │   └── editor-provider.tsx              # Core editor context wiring
│   └── ui/                     # Sidebar/tooltip/button primitives
├── contexts/
│   ├── editor-context.tsx
│   ├── renderer-context.tsx
│   ├── media-adaptor-context.tsx
│   └── sidebar-context.tsx
├── hooks/
│   ├── use-overlays.tsx
│   ├── use-rendering.tsx
│   └── use-extended-theme-switcher.ts
├── utils/
│   └── http-renderer.ts           # HTTP renderer implementing VideoRenderer
├── types/
│   ├── renderer.ts                # VideoRenderer interface
│   ├── overlay-adaptors.ts        # Overlay adaptor interfaces
│   └── index.ts                   # OverlayType, Overlay, etc.
└── constants.ts                   # DEFAULT_OVERLAYS, colors, etc.

Props

The ReactVideoEditor component extends the editor provider props and adds UI-level controls. Required props are marked with *.

PropTypeDefaultDescription
Core
projectId*string-Composition/session ID used for renders and state
rendererVideoRenderer-Deprecated — use customRenderer instead
fpsnumber30Frames per second for playback and renders
editorStateEditorState-Initial editor state. Pass the object from onSave to restore a previous session
Autosave
autoSaveIntervalnumber10000Autosave interval in milliseconds
onSave(state: EditorState) => void-Called on every save (autosave or manual). Receives the full serialized editor state — use this to persist to your backend
Sidebar and Layout
showSidebarbooleantrueToggle the default sidebar
customSidebarReactNode-Provide your own sidebar; hides the default
sidebarLogoReactNode-Custom logo for the default sidebar
sidebarFooterTextstring-Footer text in the default sidebar
disabledPanelsOverlayType[]-Hide specific overlay panels
showIconTitlesbooleantrueShow/hide sidebar icon titles
sidebarWidthstring"16rem"CSS width var for content sidebar
sidebarIconWidthstring"3rem"CSS width var for icon rail
classNamestring-Applied to main content inset
Player / Mode
isPlayerOnlybooleanfalseFullscreen player without editor UI
isLoadingProjectbooleanfalseWhether the project from URL is still loading
Renderer & API
customRendererVideoRenderer-Optional cloud/server renderer (SSR, Lambda, or custom). Not required — the SDK uses client-side rendering by default
enableWebRenderbooleantrue if no customRendererEnable client-side video export via WebCodecs. Enabled by default when no customRenderer is provided
showRenderSettingsbooleantrueShow the render mode toggle in the settings panel
baseUrlstring-Optional API base for editor operations
Media Adaptors
adaptorsOverlayAdaptors-Pluggable sources for content (video, images, audio, text, stickers, templates, animations)
Timeline
initialRowsnumber5Initial number of timeline rows
maxRowsnumber8Maximum number of timeline rows
Zoom
zoomConstraintsobject{ min: 0.2, max: 10, step: 0.1, default: 1 }Zoom level constraints
Snapping
snappingConfigobject{ thresholdFrames: 1, enableVerticalSnapping: true }Timeline snapping configuration
Feature Flags
disableMobileLayoutbooleanfalseDisable mobile-specific layout
disableVideoKeyframesbooleanfalseDisable video keyframe functionality
enablePushOnDragbooleanfalseEnable push-on-drag timeline behavior
Video Dimensions
videoWidthnumber1280Video output width
videoHeightnumber720Video output height
Theming
availableThemesCustomTheme[]-List of custom themes
selectedThemestring | undefined-Active theme id
onThemeChange(themeId: string) => void-Theme change callback
showDefaultThemesbooleantrueShow/hide default themes
hideThemeTogglebooleanfalseHide theme toggle UI
defaultThemestring"dark"Default theme to use
Status UI
showAutosaveStatusbooleantrueShow autosave indicator

Notes

  • The SDK ships with client-side rendering enabled by default. You do not need to provide a renderer to get video export working.
  • The component internally manages a playerRef and wires it into the VideoPlayer. If you need direct player access, read it from the editor context or adapt the provider usage directly.
  • Pass a previously-saved EditorState via the editorState prop to seed the editor with initial content.
  • The HttpRenderer is a convenience implementation of VideoRenderer that expects REST endpoints at /render and /progress. It is only needed if you want server-side rendering.

EditorState In, EditorState Out

The onSave callback emits an EditorState on every autosave tick and manual save. Pass that same object back via the editorState prop to restore a session — no destructuring or field mapping required.

import { ReactVideoEditor } from '@reactvideoeditor/react-video-editor/react-video-editor';
import type { EditorState } from '@reactvideoeditor/react-video-editor/types';

function Editor({ savedState }: { savedState?: EditorState }) {
  const handleSave = (state: EditorState) => {
    // Persist to your backend
    fetch('/api/projects/my-project', {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(state),
    });
  };

  return (
    <ReactVideoEditor
      projectId="my-project"
      editorState={savedState}
      onSave={handleSave}
    />
  );
}

The editor uses timestamp-based conflict resolution to decide whether to restore from local IndexedDB or use the provided editorState:

  • editorState with savedAt — compared against the local autosave timestamp. Whichever is newer wins. Local changes made after the last server save are preserved; fresh server data takes priority over stale local state.
  • editorState without savedAt — IndexedDB is always restored if a local save exists. The prop is treated as a fallback for when no local state is available.
  • editorState omitted — falls back to IndexedDB or internal defaults.

The savedAt field is stamped automatically on every save and included in the onSave payload — persist it alongside the rest of the state and pass it back.

The EditorState type contains source-of-truth fields only (no derived values):

interface EditorState {
  tracks: Track[];
  aspectRatio: AspectRatio;    // '16:9' | '1:1' | '4:5' | '9:16'
  backgroundColor: string;
  playbackRate: number;
  savedAt?: number;            // Unix-ms timestamp, set automatically on every save
}

Need pixel dimensions for an aspect ratio? Use the exported getCanvasDimensions utility:

import { getCanvasDimensions } from '@reactvideoeditor/react-video-editor/types';

const { width, height } = getCanvasDimensions('16:9');
// → { width: 1920, height: 1080 }

OPFS asset URLs

Asset URLs from the browser's Origin Private File System (OPFS) are dehydrated to asset:{id} references in the state. If your workflow uses external URLs (e.g. https://), they pass through as-is. OPFS-based assets will need a URL resolution strategy on your backend — this is a separate concern from state persistence.

Deprecated: onSaving / onSaved

The onSaving and onSaved props have been removed. Use onSave instead — it provides the full EditorState on every save, replacing both callbacks with a single, more useful one.

Next Steps

  • Get started with the default sidebar panels and overlays — client-side export works out of the box.
  • Optionally wire up a server renderer (SSR or Lambda) via customRenderer for production workloads.
  • Add media sources via adaptors (e.g. Pexels for images/videos).
  • Customize themes and integrate your app's theme switching UX.