Using RVE in a Pure React App
Step-by-step guide to integrate React Video Editor (RVE) into any React app — no Next.js or Vite required.
Overview
This guide shows how to add React Video Editor (RVE) to any React application, regardless of your bundler or toolchain. Whether you're using Create React App, Parcel, esbuild, Rspack, or a custom Webpack setup — RVE works anywhere React runs.
You will:
- Confirm your bundler can handle CSS imports
- Set up Tailwind CSS
- Configure TypeScript path aliases
- Add RVE dependencies and migrate code
Prerequisites: Node.js 18+, npm or pnpm, a working React 18+ or 19+ app with a module bundler.
No framework lock-in
RVE has zero framework-specific code internally. It doesn't import from next/, doesn't use import.meta.env, and doesn't rely on any Vite or Next.js APIs. Any bundler that can process React + CSS will work.
Nudge for a Video Tutorial
Tired of reading long wordy docs? Same. Email hello@reactvideoeditor.com and tell Sam (our founder) to make some video tutorials.
Quick checklist
- React 18+ or 19+ app with a module bundler
- Tailwind CSS configured and imported
-
@alias points to./src - RVE deps installed and editor component wired
- Rendering backend endpoint configured
1) Confirm your bundler handles CSS imports
RVE ships a pre-built styles.css. Your bundler needs to handle CSS imports — all modern bundlers do this out of the box:
- Webpack (CRA, custom): Built-in via
css-loader+style-loader - Parcel: Built-in, zero config
- esbuild: Built-in with
--bundle - Rspack: Built-in
No special plugin is needed.
2) Install Tailwind CSS
If your project doesn't already use Tailwind, install it with PostCSS:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -ppnpm add -D tailwindcss postcss autoprefixer
npx tailwindcss init -pyarn add -D tailwindcss postcss autoprefixer
npx tailwindcss init -pIn tailwind.config.js, include your source paths:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{ts,tsx,js,jsx}",
],
theme: { extend: {} },
plugins: [],
};In your main CSS file (e.g. src/index.css), import Tailwind:
@tailwind base;
@tailwind components;
@tailwind utilities;3) Configure TypeScript path alias
In your tsconfig.json, add the @ alias:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}You also need to configure your bundler to resolve the same alias. Here are examples for common setups:
CRA supports the @ alias automatically if you set baseUrl in tsconfig.json. If using a CRA fork or CRACO:
// craco.config.js
const path = require("path");
module.exports = {
webpack: {
alias: {
"@": path.resolve(__dirname, "src"),
},
},
};// webpack.config.js
const path = require("path");
module.exports = {
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
},
},
};Parcel reads tsconfig.json paths automatically — no extra config needed.
// build.js
require("esbuild").build({
// ...
alias: {
"@": "./src",
},
});Also install Node types:
npm install -D @types/nodepnpm add -D @types/nodeyarn add -D @types/node4) Initialize shadcn/ui (optional)
npx shadcn@latest initChoose any color/theme you prefer.
5) Add dependencies
Copy the dependencies from your RVE Pro project's package.json into your app's package.json.
Ensure you use the latest package.json
The dependencies section may look something like this (note that versions and packages may vary) so its important you check the package.json from the RVE Pro repo.
{
"dependencies": {
"@radix-ui/react-alert-dialog": "^1.1.2",
"@remotion/bundler": "4.0.356",
"@remotion/cli": "4.0.356",
"@remotion/google-fonts": "4.0.356",
"@remotion/lambda": "4.0.356",
"@remotion/player": "4.0.356",
"@remotion/renderer": "4.0.356",
"date-fns": "^4.1.0",
"mediabunny": "^1.11.2",
"posthog-js": "^1.268.6",
"react-best-gradient-color-picker": "^3.0.14",
"react-hotkeys-hook": "^4.6.1",
"remotion": "4.0.356",
"tailwindcss-animate": "^1.0.7",
"uuid": "^10.0.0",
"zustand": "^4.4.6"
}
}Then install:
npm i6) Copy RVE source
- From your RVE Pro project, copy the
reactvideoeditordirectory into your app undersrc/reactvideoeditor. - Copy
constants.tsinto your app'ssrcdirectory.
7) Wire up the editor
Create your editor component (e.g. src/Editor.tsx):
import React from "react";
import { HttpRenderer } from "@/reactvideoeditor/pro/utils/http-renderer";
import { ReactVideoEditor } from "@/reactvideoeditor/pro/components/react-video-editor";
import { createPexelsVideoAdaptor } from "@/reactvideoeditor/pro/adaptors/pexels-video-adaptor";
import { createPexelsImageAdaptor } from "@/reactvideoeditor/pro/adaptors/pexels-image-adaptor";
import { DEFAULT_OVERLAYS } from "@/constants";
import "@/reactvideoeditor/pro/styles.css";
import logo from "./assets/logo.png";
export default function Editor() {
// A project ID represents a unique editing session/workspace and
// must match the composition ID defined in the Remotion bundle.
const PROJECT_ID = "TestComponent";
// Point this to your own rendering backend.
// This is NOT a Next.js API route — use any HTTP endpoint you control.
const ssrRenderer = React.useMemo(
() =>
new HttpRenderer("/api/render", {
type: "ssr",
entryPoint: "/api/render",
}),
[]
);
return (
<div className="w-full h-full fixed inset-0">
<ReactVideoEditor
projectId={PROJECT_ID}
defaultOverlays={DEFAULT_OVERLAYS as any}
fps={30}
renderer={ssrRenderer}
disabledPanels={[]}
defaultTheme="dark"
sidebarLogo={<img src={logo} alt="Logo" className="w-6 h-6" />}
adaptors={{
video: [createPexelsVideoAdaptor("your-pexels-api-key")],
images: [createPexelsImageAdaptor("your-pexels-api-key")],
}}
showDefaultThemes
sidebarWidth="clamp(350px, 25vw, 500px)"
sidebarIconWidth="57.6px"
showIconTitles={false}
/>
</div>
);
}Then render it from your app entry point (e.g. src/App.tsx or src/index.tsx):
import Editor from "./Editor";
function App() {
return <Editor />;
}
export default App;8) Set up your rendering backend
Unlike Next.js, you don't have a built-in API route. You need an HTTP endpoint that handles rendering requests. The HttpRenderer will POST to whatever URL you provide.
Options:
- A separate Express/Fastify/Hono server
- A serverless function (AWS Lambda, Cloudflare Workers, etc.)
- Any HTTP endpoint that can invoke Remotion's renderer
Example with Express:
import express from "express";
const app = express();
app.use(express.json());
app.post("/api/render", async (req, res) => {
// TODO: Wire to your Remotion rendering logic
res.json({ ok: true });
});
app.listen(3001);Point your HttpRenderer URL to this server (e.g. http://localhost:3001/api/render in development).
9) Environment variables
RVE Pro was originally built on Next.js, which uses process.env.NEXT_PUBLIC_*. In a pure React app, you need to use whatever convention your bundler supports:
| Bundler | Convention | Example |
|---|---|---|
| CRA (Webpack) | process.env.REACT_APP_* | process.env.REACT_APP_PEXELS_API_KEY |
| Parcel | process.env.* | process.env.PEXELS_API_KEY |
| Webpack (custom) | DefinePlugin | Whatever you configure |
| esbuild | --define | Whatever you configure |
When migrating RVE Pro code, find and replace all occurrences of process.env.NEXT_PUBLIC_ with your bundler's convention.
10) Add your logo
Place a logo at src/assets/logo.png (or update the import path) and ensure the sidebarLogo prop points to it.
11) Run the app
npm startThe port depends on your setup (CRA defaults to http://localhost:3000).
Notes and troubleshooting
-
No
'use client'needed: Unlike Next.js, you don't need"use client"directives — everything is client-side in a pure React app. The'use client'strings in RVE's output are harmless and ignored by non-Next.js bundlers. -
Rendering backend: The
HttpRendererexample needs a real backend endpoint. Unlike Next.js where you get API routes for free, you need to set up your own server or serverless function. -
Path alias issues: If imports using
@/fail, confirm both yourtsconfig.jsonand your bundler's alias config match. -
Styles not applying: Ensure your main CSS file includes Tailwind directives and that
styles.cssfrom RVE is imported in your editor component. -
ESM vs CJS: RVE ships both formats. If your bundler has trouble with one, check its module resolution settings. Most modern bundlers prefer ESM (
.mjs) automatically.