Skip to content

dominictobias/react-video-trim

Repository files navigation

React Video Trim

A React component for selecting trim ranges on a video with a filmstrip timeline.

demo

The core library reports the selected { startTime, endTime } range. The included WebCodecs plugin can turn that range into a trimmed video file in the browser.

Install

# npm
npm install react-video-trim

# yarn
yarn add react-video-trim

# pnpm
pnpm add react-video-trim

# bun
bun add react-video-trim

Bundler

This package ships as ESM only. Use it with Vite, Next.js, webpack, or any modern bundler that supports import.

Import the component and its styles:

import { VideoTrim } from 'react-video-trim'
import 'react-video-trim/style.css'

The WebCodecs trimming plugin is a separate entry point so the core bundle does not load video processing code unless you import it:

import { createTrimHandler } from 'react-video-trim/plugins/webcodecs'

Props

VideoTrim

Prop Type Required Description
src string | File | Blob Yes Video source URL, file, or blob.
onTrim (range: TrimRange) => void Yes Called when the user confirms a trim. Receives { startTime, endTime } in seconds.
onCancel () => void No Called when the user cancels. Renders a Cancel button when provided.
labels VideoTrimLabelsProp No Overrides visible text, ARIA labels, loading copy, and video error messages. Uses English defaults.
className string No Applied to the root element.
style CSSProperties No Inline styles for the root element.

TrimRange

Field Type Description
startTime number Trim start time in seconds.
endTime number Trim end time in seconds.

Labels

labels accepts a partial object, so you only need to provide the text you want to replace. Missing values fall back to defaultVideoTrimLabels.

import { VideoTrim, defaultVideoTrimLabels } from 'react-video-trim'

;<VideoTrim
  src={videoFile}
  onTrim={setTrimRange}
  labels={{
    actions: {
      trim: 'Guardar recorte',
      cancel: 'Cancelar',
    },
    playback: {
      play: 'Reproducir',
      pause: 'Pausar',
    },
    video: {
      ariaLabel: 'Vista previa del video',
    },
    toolbar: {
      ariaLabel: 'Controles para recortar video',
    },
    filmstrip: {
      loadingFrames: ({ loaded, total }) =>
        `Cargando fotogramas ${loaded}/${total}`,
    },
    errors: {
      ...defaultVideoTrimLabels.errors,
      load: 'No se pudo cargar este video.',
    },
  }}
/>

Example

import { useState } from 'react'
import { VideoTrim } from 'react-video-trim'
import type { TrimRange } from 'react-video-trim'
import 'react-video-trim/style.css'

export function App() {
  const [videoFile, setVideoFile] = useState<File | null>(null)
  const [trimRange, setTrimRange] = useState<TrimRange | null>(null)

  return (
    <div>
      <input
        type="file"
        accept="video/*"
        onChange={(event) => setVideoFile(event.target.files?.[0] ?? null)}
      />

      {videoFile ? <VideoTrim src={videoFile} onTrim={setTrimRange} /> : null}

      {trimRange ? <pre>{JSON.stringify(trimRange, null, 2)}</pre> : null}
    </div>
  )
}

WebCodecs Trimming

Use createTrimHandler as an onTrim adapter when you want WebCodecs to produce a trimmed file:

import { useMemo, useState } from 'react'
import { VideoTrim } from 'react-video-trim'
import {
  type TrimVideoResult,
  createTrimHandler,
} from 'react-video-trim/plugins/webcodecs'
import 'react-video-trim/style.css'

export function App() {
  const [videoFile, setVideoFile] = useState<File | null>(null)
  const [result, setResult] = useState<TrimVideoResult | null>(null)

  const onTrim = useMemo(() => {
    if (!videoFile) return undefined

    return createTrimHandler({
      src: videoFile,
      outputFormat: 'mp4',
      onComplete: setResult,
      onError: console.error,
      onProgress: ({ progress }) => {
        console.log(`Trimming… ${Math.round(progress * 100)}%`)
      },
    })
  }, [videoFile])

  if (!videoFile || !onTrim) return null

  return (
    <VideoTrim
      src={videoFile}
      onTrim={(range) => {
        void onTrim(range)
      }}
    />
  )
}

Or call trimVideo directly when you do not need the React handler adapter:

import { trimVideo } from 'react-video-trim/plugins/webcodecs'

const result = await trimVideo(videoFile, {
  startTime: 2.5,
  endTime: 12,
})

const url = URL.createObjectURL(result.blob)

The WebCodecs implementation uses Mediabunny to trim media in modern browsers without shipping a large video processing runtime. It can copy media data when possible and transcode when needed, depending on the browser codecs and selected output format.

Alternatives

WebCodecs is the default recommendation for this package because it keeps the browser bundle small and uses native media APIs. Depending on your product requirements, you may still consider another trimming strategy in your own app.

FFmpeg

FFmpeg.wasm runs FFmpeg in the browser through WebAssembly.

Pros:

  • Handles a broad range of containers, codecs, and transformations.
  • Gives you FFmpeg's familiar command model when you need advanced processing.
  • Can be a good fit for apps that need maximum format coverage and can tolerate heavier downloads.

Cons:

  • Adds a large (~38-42mb) WebAssembly payload compared with WebCodecs.
  • Usually has a slower startup because the FFmpeg runtime must load before work begins.
  • Increases memory and CPU pressure, especially on mobile devices.

MediaRecorder

MediaRecorder can replay the selected range through a media element or canvas stream and record the result with native browser APIs.

Pros:

  • No large processing runtime to download.
  • Works with browser-native APIs and can support files the browser can play.
  • Useful as a simple compatibility fallback for basic recording workflows.

Cons:

  • Runs in real time, so trimming a 20 second range takes about 20 seconds.
  • Output format and codec choices are limited by each browser's MediaRecorder support.
  • Re-recording can reduce quality and may not preserve the original media streams exactly.

Development

Clone the repo, install dependencies, and start the demo app:

git clone <repo-url>
cd react-video-trim
bun install
bun run dev

Other useful commands:

bun run build   # type-check and build dist/react-video-trim.js + dist/plugins/webcodecs.js
bun run lint
bun run preview # preview the production build locally

The demo lives in src/Demo.tsx and uses WebCodecs to trim and preview the output.

About

A React component for trimming videos

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages