Skip to content
NewMastershot Studio is open: a video editor with no watermark on anything you export. Try it free

React, Vue, Svelte and others

Load the editor in a component, give it the file, and remove it when the component goes away.

The editor loads from its URL rather than from npm, so in a framework you import it with a dynamic import() once the component is on the page, and call destroy() when it goes away. The comments in the import() tell Vite and webpack to leave the URL alone.

React and Next.js

tsx
import { useEffect, useRef } from "react"

const editorUrl = "https://cdn.mastershot.app/editor/1.1.0/editor.js"

export function PhotoEditor({
  file,
  onSave,
}: {
  file: File
  onSave: (file: File) => void
}) {
  const box = useRef<HTMLDivElement>(null)

  useEffect(() => {
    let editor: { destroy(): void } | undefined
    let gone = false
    import(/* @vite-ignore */ /* webpackIgnore: true */ editorUrl).then(
      ({ appendDefaultEditor }) => {
        if (gone || !box.current) return
        editor = appendDefaultEditor(box.current, {
          src: file,
          licenseKey: process.env.NEXT_PUBLIC_MASTERSHOT_KEY,
        })
        editor.on("process", ({ dest }: { dest: File }) => onSave(dest))
      }
    )
    return () => {
      gone = true
      editor?.destroy()
    }
  }, [file])

  return <div ref={box} style={{ height: 600 }} />
}

In Next.js, put "use client" at the top of the file. The editor runs only in the browser.

Vue

vue
<script setup>
import { onMounted, onBeforeUnmount, ref } from "vue"

const props = defineProps({ file: File })
const emit = defineEmits(["save"])
const box = ref()
let editor

onMounted(async () => {
  const { appendDefaultEditor } = await import(
    /* @vite-ignore */ "https://cdn.mastershot.app/editor/1.1.0/editor.js"
  )
  editor = appendDefaultEditor(box.value, { src: props.file })
  editor.on("process", ({ dest }) => emit("save", dest))
})

onBeforeUnmount(() => editor?.destroy())
</script>

<template>
  <div ref="box" style="height: 600px" />
</template>

In Nuxt, wrap the component in <ClientOnly>.

Svelte

svelte
<script>
  import { onMount } from "svelte"

  let { file, onsave } = $props()
  let box

  onMount(() => {
    let editor
    import(/* @vite-ignore */ "https://cdn.mastershot.app/editor/1.1.0/editor.js").then(
      ({ appendDefaultEditor }) => {
        editor = appendDefaultEditor(box, { src: file })
        editor.on("process", ({ dest }) => onsave(dest))
      }
    )
    return () => editor?.destroy()
  })
</script>

<div bind:this={box} style="height: 600px"></div>

Angular and others

Anything that can run code once an element is on the page can host the editor: call appendDefaultEditor(element, options) then, and destroy() when the element goes. The <mastershot-editor> element works too, in any framework that renders custom elements. See Add the editor to your site.

TypeScript

The script has no type declarations yet, so TypeScript sees what import() returns as any. The reference lists everything it has.

Changing the file

To open a different file in an editor that's already there, call editor.loadImage(file) instead of making a new editor. Changing options such as utils or imageCropAspectRatio on the editor takes effect straight away, with the edits kept.

Stuck, or something isn't working? Email [email protected] with what you tried. If a photo or video won't open, send it if you can, and we'll make it work.