The full editor
One component with every tool. Use it as is, or trim it down.
"use client";
import { ImageEditor } from "@/components/image-editor/image-editor";
export default function FullEditorExample() {
return <ImageEditor className="h-[680px] overflow-hidden rounded-xl border" src="/samples/mountain-lake.jpg" />;
}Trim it, extend it
Pass tools to choose which tools appear in the switcher, and panels to replace a built-in panel or add a panel for your own tool. Custom panels call useImageEditor() like the built-in ones do.
"use client";
import { CropIcon, SlidersHorizontalIcon, StickerIcon, WandSparklesIcon } from "lucide-react";
import { useImageEditor } from "photocn/react";
import { Button } from "@/components/ui/button";
import { ImageEditor } from "@/components/image-editor/image-editor";
// The full editor, trimmed to three built-in tools plus one of your own.
export default function CustomToolsExample() {
return (
<ImageEditor
className="h-[640px] overflow-hidden rounded-xl border"
defaultTool="filters"
panels={{ stamp: <StampPanel /> }}
showRecipes={false}
src="/samples/dog.jpg"
tools={[
{ value: "filters", label: "Filters", icon: WandSparklesIcon },
{ value: "adjust", label: "Adjust", icon: SlidersHorizontalIcon },
{ value: "compose", label: "Crop", icon: CropIcon },
{ value: "stamp", label: "Looks", icon: StickerIcon },
]}
/>
);
}
// Custom panels get the same API as the built-in ones.
function StampPanel() {
const editor = useImageEditor();
const looks = {
Moody: { exposure: -0.15, contrast: 0.35, shadows: -0.2 },
Airy: { exposure: 0.2, contrast: -0.15, highlights: -0.3 },
Punchy: { contrast: 0.45, bloom: 0.15 },
} as const;
return (
<div className="flex flex-col gap-2 p-4">
<h2 className="text-sm font-semibold">One-tap looks</h2>
{Object.entries(looks).map(([name, look]) => (
<Button
key={name}
onClick={() => editor.adjust.setLights({ ...editor.adjust.value.lights, ...look })}
variant="outline"
>
{name}
</Button>
))}
</div>
);
}Props
ImageEditor accepts every option of useImageEditorState (see the API reference), plus:
| Prop | Type | Description |
|---|---|---|
| editor | ImageEditorApi | State you created with useImageEditorState(). Otherwise the editor owns its state. |
| tools | EditorToolbarTool[] | Tools in the sidebar switcher. Default: all built-in tools. |
| panels | Record<toolId, ReactNode> | Replace or add sidebar panels per tool id. |
| showOpenButton | boolean | Show the Open button and the empty-state picker. Default true. |
| showRecipes | boolean | Show the recipe save/load buttons. Default true. |
| showHistogram | boolean | Show the histogram strip. Default true. |
| toolbarExtra | ReactNode | Extra toolbar content, placed before Export. |
| sidebarExtra | ReactNode | Content below the active panel. |
| onSave | (result) => void | Promise<void> | Adds a Save button to the export dialog, e.g. to upload the result. |
| children | ReactNode | Rendered inside the provider, e.g. <ImageEditorCommandMenu />. |