Overview
The ImageEditor component provides a powerful image editing interface with support for filters, effects, text, shapes, and more.
Import
'use client';
import dynamic from 'next/dynamic';
const ImageEditor = dynamic(
() => import('@distralabs/media-editor').then(mod => ({ default: mod.ImageEditor })),
{ ssr: false }
);
Always use dynamic import with ssr: false to avoid server-side rendering issues.
Props
Required Props
Your SDK license key (JWT format). Contact your account manager to obtain a license key.licenseKey="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Callback function called when the user closes the editor.onClose={() => setShowEditor(false)}
Optional Props
Override the default license validation API endpoint.Default: https://api.kloudleads.com/license/validateapiUrl="https://localhost:3030/social"
The SDK appends /license/validate to this URL. If your endpoint is https://localhost:3030/social/license/validate, use apiUrl="https://localhost:3030/social".
Initial image file to load into the editor.const [file, setFile] = useState<File | null>(null);
<ImageEditor
files={file}
// ...
/>
callback
(result: CallbackProps, extras?: EditorExtras) => void
Callback function called when the user exports the edited image.CallbackProps:interface CallbackProps {
base64: string; // Data URL of exported image
width: number; // Canvas width
height: number; // Canvas height
template?: any; // Scene data if template used
}
EditorExtras:interface EditorExtras {
thumbnail?: string; // Thumbnail preview
format?: string; // Image format (png, jpg, etc)
}
Example:const handleExport = (result: CallbackProps, extras?: EditorExtras) => {
// Download the image
const link = document.createElement('a');
link.href = result.base64;
link.download = 'edited-image.png';
link.click();
// Or upload to server
fetch('/api/upload', {
method: 'POST',
body: JSON.stringify({ image: result.base64 }),
});
};
Custom theme object to override default colors and styling.const customTheme = {
'background.primary': '#0f172a',
'background.secondary': '#1e293b',
'text.primary': '#ffffff',
'accent.primary': '#3b82f6',
};
<ImageEditor theme={customTheme} />
See Theme Customization for all available keys.
Show theme customization UI to users. Set to false for production.showThemeCreator={false} // Hide theme UI
Enable headless (programmatic) mode. The editor will execute predefined functions without showing the UI.<ImageEditor
headless={true}
calls={[
() => handleAddText(['Headline']),
() => handleAddShape('rectangle'),
]}
/>
Array of functions to execute in headless mode.calls={[
() => handleAddText(['Text 1', 'Text 2']),
() => handleAddShape('rectangle'),
() => applyFilter('grayscale'),
]}
Array of brand presets for consistent styling.interface BrandDetails {
id: string;
name: string;
primaryColor?: string;
secondaryColor?: string;
fontFamily?: string;
logo?: string;
}
const brands = [
{
id: 'brand-1',
name: 'My Brand',
primaryColor: '#3b82f6',
fontFamily: 'Inter',
},
];
<ImageEditor brands={brands} />
Load a template on editor startup.interface Template {
id?: string;
name?: string;
sceneData: EditorItem[];
width: number;
height: number;
thumbnail?: string;
brandId?: string;
}
<ImageEditor defaultTemplate={myTemplate} />
onExport
(templateId: string, brandResults: any, updatedImage: string, thumbUri: string) => void
Advanced export callback with additional metadata.const handleExport = (templateId, brandResults, updatedImage, thumbUri) => {
console.log('Template ID:', templateId);
console.log('Brand results:', brandResults);
console.log('Image:', updatedImage);
console.log('Thumbnail:', thumbUri);
};
onSaveTemplate
(props: { brandId: string; template: Template }) => Promise<void>
Callback when user saves a template.const handleSaveTemplate = async ({ brandId, template }) => {
await fetch('/api/templates', {
method: 'POST',
body: JSON.stringify({ brandId, template }),
});
};
onGetTemplates
(brandIdList?: string[]) => Promise<{ success: { data: Template[] } }>
Callback to fetch templates for display.const handleGetTemplates = async (brandIds) => {
const response = await fetch('/api/templates?' + new URLSearchParams({
brandIds: brandIds?.join(',') || ''
}));
return response.json();
};
AI-powered content creation function (advanced feature).
Complete Example
'use client';
import { useState, useCallback, useRef } from 'react';
import dynamic from 'next/dynamic';
const ImageEditor = dynamic(
() => import('@distralabs/media-editor').then(mod => ({ default: mod.ImageEditor })),
{ ssr: false }
);
const customTheme = {
'background.primary': '#0f172a',
'background.secondary': '#1e293b',
'text.primary': '#ffffff',
'accent.primary': '#3b82f6',
};
export default function ImageStudioPage() {
const fileInputRef = useRef<HTMLInputElement>(null);
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [showEditor, setShowEditor] = useState(false);
const [exportedImage, setExportedImage] = useState<string | null>(null);
const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file && file.type.startsWith('image/')) {
setSelectedFile(file);
setShowEditor(true);
}
};
const handleExport = useCallback((result: any) => {
if (result.base64) {
setExportedImage(result.base64);
setShowEditor(false);
// Download
const link = document.createElement('a');
link.href = result.base64;
link.download = `edited-${Date.now()}.png`;
link.click();
}
}, []);
const handleClose = () => {
setShowEditor(false);
setSelectedFile(null);
};
return (
<div className="min-h-screen p-6">
{!showEditor && (
<div>
<h1 className="text-3xl font-bold mb-4">Image Studio</h1>
<input
ref={fileInputRef}
type="file"
accept="image/*"
onChange={handleFileSelect}
className="hidden"
/>
<button
onClick={() => fileInputRef.current?.click()}
className="px-6 py-3 bg-blue-500 text-white rounded-lg"
>
Choose Image
</button>
</div>
)}
{showEditor && selectedFile && (
<div className="fixed inset-0 z-50">
<ImageEditor
licenseKey={process.env.NEXT_PUBLIC_LICENSE_KEY || ''}
apiUrl="https://localhost:3030/social"
files={selectedFile}
onClose={handleClose}
callback={handleExport}
theme={customTheme}
showThemeCreator={false}
/>
</div>
)}
</div>
);
}
Features
Image Editing
- Upload & Load: Support for JPG, PNG, GIF, WebP
- Resize: Custom dimensions or preset aspect ratios
- Crop: Freeform or ratio-locked cropping
- Rotate: 90° increments or custom angles
- Flip: Horizontal and vertical flipping
Effects & Filters
- Color Filters: Grayscale, Sepia, Invert, Colorize
- Adjustments: Brightness, Contrast, Saturation, Hue
- Blur: Gaussian blur with adjustable radius
- Artistic: Pixelate, Noise, Emboss, Posterize
- Shadows: Drop shadows with offset, blur, color
Text
- Rich Text: Multiple fonts, sizes, colors, weights
- Google Fonts: Dynamic font loading
- Formatting: Bold, italic, underline, alignment
- Effects: Shadows, outlines, backgrounds
Shapes
- Basic Shapes: Rectangle, Circle, Triangle, Star, Arrow
- Customization: Fill color, stroke, stroke width
- Advanced: Custom paths and SVG shapes
Layers
- Multi-layer Support: Unlimited layers
- Z-Index Control: Bring forward, send backward
- Layer Management: Show/hide, lock, duplicate, delete
Background
- Solid Colors: Any color picker
- Gradients: Linear and radial gradients
- Images: Background image with fit modes
Export
- Formats: PNG, JPG, WebP
- Quality: Adjustable compression
- Dimensions: Original or custom size
Browser Support
- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
Mobile browsers have limited support. Desktop browsers recommended for best experience.
Next Steps