React

The React package is the reference implementation. Tested against React 18 and React 19 with concurrent rendering enabled.

Install

Terminal
npm install @editpix/react

Basic usage

ProductImageEditor.tsx
"use client";

import { useState } from "react";
import { EditpixEditor } from "@editpix/react";

export function ProductImageEditor({ productId }: { productId: string }) {
  const [open, setOpen] = useState(false);
  const [preview, setPreview] = useState<string | null>(null);

  return (
    <>
      <button onClick={() => setOpen(true)} className="rounded-md border px-3 py-2">
        Edit image
      </button>

      {open && (
        <EditpixEditor
          apiKey={import.meta.env.VITE_EDITPIX_KEY}
          imageUrl={`/products/${productId}/hero.jpg`}
          options={{
            aspectRatios: ["free", "1:1", "4:3"],
            filters: true,
            annotations: true,
            resize: true,
          }}
          onSave={async (blob) => {
            const form = new FormData();
            form.append("file", blob, "hero.png");
            await fetch(`/api/products/${productId}/image`, {
              method: "POST",
              body: form,
            });
            setPreview(URL.createObjectURL(blob));
            setOpen(false);
          }}
          onClose={() => setOpen(false)}
        />
      )}

      {preview && <img src={preview} alt="" className="mt-4 rounded" />}
    </>
  );
}

With a modal wrapper

Editpix ships headless — it fills its parent container. Wrap it in your own dialog component, or the <dialog> element, for a full-screen editor flow.

EditorDialog.tsx
import { useRef, useEffect } from "react";
import { EditpixEditor } from "@editpix/react";

export function EditorDialog({ open, onClose, imageUrl, onSave }: Props) {
  const ref = useRef<HTMLDialogElement>(null);

  useEffect(() => {
    if (open) ref.current?.showModal();
    else ref.current?.close();
  }, [open]);

  return (
    <dialog ref={ref} className="w-[min(1200px,96vw)] h-[86vh] p-0 rounded-xl">
      <EditpixEditor
        apiKey={KEY}
        imageUrl={imageUrl}
        onSave={(blob) => { onSave(blob); onClose(); }}
        onClose={onClose}
      />
    </dialog>
  );
}

Server Components

EditpixEditor is a client component. In Next.js App Router, import it from a "use client" boundary. See the Next.js guide for a dynamic import pattern that keeps your initial payload lean.