Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.clipora.dev/docs/llms.txt

Use this file to discover all available pages before exploring further.

This guide is for React.js applications (Create React App, Vite, custom setups).For Next.js, see the Next.js ImageEditor Integration guide.

Prerequisites

Node.js 16+

Node.js version 16.x or higher

React 18.2.0

React version 18.2.0 (not React 19)

Installation

1

Install the SDK

npm install @distralabs/media-editor
2

Install Required Dependencies

npm install framer-motion lucide-react
3

Verify React Version

Check your React version:
npm list react
If you need to install React 18.2.0:
npm install react@18.2.0 react-dom@18.2.0

Basic Setup

Import SDK Styles

Add the SDK CSS to your application entry point:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';

// Import media-editor SDK styles
import '@distralabs/media-editor/dist/index.css';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Import the Editor

import { ImageEditor } from '@distralabs/media-editor';

ImageEditor Interface

Core Props

interface ImageEditorProps {
  // Required
  licenseKey: string;              // Your SDK license key (JWT)
  onClose: () => void;             // Called when user closes editor

  // Optional
  apiUrl?: string;                 // Override license validation API URL
  files?: File;                    // Initial image file to load
  callback?: (result: CallbackProps, extras?: EditorExtras) => void;
  theme?: Record<string, string>;  // Custom theme colors
  showThemeCreator?: boolean;      // Show theme customization UI
  headless?: boolean;              // Enable programmatic mode
  brands?: BrandDetails[];         // Brand presets
  defaultTemplate?: Template;      // Load template on start
}
interface CallbackProps {
  base64: string;        // Exported image as base64 data URL
  width: number;         // Canvas width
  height: number;        // Canvas height
  template?: any;        // Scene data if template was used
}

interface EditorExtras {
  thumbnail?: string;    // Thumbnail preview
  format?: string;       // Image format (png, jpg, etc)
}

Step-by-Step Integration

Step 1: Create Your Component

src/components/ImageStudio.js
import React, { useState, useCallback, useRef } from 'react';
import { ImageEditor } from '@distralabs/media-editor';
import '@distralabs/media-editor/dist/index.css';

function ImageStudio() {
  const fileInputRef = useRef(null);
  const [selectedFile, setSelectedFile] = useState(null);
  const [showEditor, setShowEditor] = useState(false);
  const [exportedImage, setExportedImage] = useState(null);

  // Continue to Step 2...
}

export default ImageStudio;

Step 2: Implement File Selection

const handleFileSelect = (e) => {
  const file = e.target.files?.[0];
  if (file && file.type.startsWith('image/')) {
    setSelectedFile(file);
    setShowEditor(true);
  }
};

const handleDrop = (e) => {
  e.preventDefault();
  const file = e.dataTransfer.files?.[0];
  if (file && file.type.startsWith('image/')) {
    setSelectedFile(file);
    setShowEditor(true);
  }
};

Step 3: Implement Callbacks

const handleExport = useCallback((result, extras) => {
  console.log('Export result:', result, extras);

  if (result.base64) {
    setExportedImage(result.base64);
    setShowEditor(false);
  }
}, []);

const handleClose = () => {
  setShowEditor(false);
  setSelectedFile(null);
};

const handleDownload = () => {
  if (exportedImage) {
    const link = document.createElement('a');
    link.href = exportedImage;
    link.download = `edited-image-${Date.now()}.png`;
    link.click();
  }
};

Step 4: Render the Editor

return (
  <div className="min-h-screen">
    {/* Upload UI */}
    {!showEditor && (
      <div>
        <input
          ref={fileInputRef}
          type="file"
          accept="image/*"
          onChange={handleFileSelect}
          style={{ display: 'none' }}
        />
        <button onClick={() => fileInputRef.current?.click()}>
          Choose Image
        </button>
      </div>
    )}

    {/* Image Editor */}
    {showEditor && selectedFile && (
      <div style={{ position: 'fixed', inset: 0, zIndex: 40 }}>
        <ImageEditor
          licenseKey="YOUR_LICENSE_KEY_HERE"
          apiUrl="https://your-api.com/social"
          files={selectedFile}
          onClose={handleClose}
          callback={handleExport}
          theme={customTheme}
          showThemeCreator={false}
        />
      </div>
    )}
  </div>
);

Theme Customization

Creating a Custom Theme

const customTheme = {
  // Backgrounds
  'background.primary': '#0f172a',
  'background.secondary': '#1e293b',
  'background.tertiary': '#334155',

  // Text
  'text.primary': '#ffffff',
  'text.secondary': '#cbd5e0',

  // Brand colors
  'accent.primary': '#3b82f6',
  'accent.secondary': '#06b6d4',
  'accent.hover': '#60a5fa',

  // Borders
  'border.default': '#334155',
  'border.subtle': '#1e293b',

  // Components
  'button.primary': '#3b82f6',
  'input.background': '#1e293b',
  'toolbar.background': '#0f172a',
  'canvas.background': '#1a202c',
};

Applying the Theme

<ImageEditor
  licenseKey={licenseKey}
  files={selectedFile}
  onClose={handleClose}
  callback={handleExport}
  theme={customTheme}
  showThemeCreator={false}
/>

Complete Example

src/components/ImageStudio.js
import React, { useState, useCallback, useRef } from 'react';
import { ImageEditor } from '@distralabs/media-editor';
import '@distralabs/media-editor/dist/index.css';
import './ImageStudio.css';

const customTheme = {
  'background.primary': '#0f172a',
  'background.secondary': '#1e293b',
  'text.primary': '#ffffff',
  'accent.primary': '#3b82f6',
};

function ImageStudio() {
  const fileInputRef = useRef(null);
  const [selectedFile, setSelectedFile] = useState(null);
  const [showEditor, setShowEditor] = useState(false);
  const [exportedImage, setExportedImage] = useState(null);

  const handleFileSelect = (e) => {
    const file = e.target.files?.[0];
    if (file && file.type.startsWith('image/')) {
      setSelectedFile(file);
      setShowEditor(true);
    }
  };

  const handleExport = useCallback((result) => {
    if (result.base64) {
      setExportedImage(result.base64);
      setShowEditor(false);
    }
  }, []);

  const handleClose = () => {
    setShowEditor(false);
    setSelectedFile(null);
  };

  const handleDownload = () => {
    if (exportedImage) {
      const link = document.createElement('a');
      link.href = exportedImage;
      link.download = `edited-image-${Date.now()}.png`;
      link.click();
    }
  };

  return (
    <div className="image-studio">
      {!showEditor && (
        <div className="upload-container">
          <input
            ref={fileInputRef}
            type="file"
            accept="image/*"
            onChange={handleFileSelect}
            style={{ display: 'none' }}
          />
          <button onClick={() => fileInputRef.current?.click()}>
            Choose Image
          </button>
        </div>
      )}

      {showEditor && selectedFile && (
        <div className="editor-overlay">
          <ImageEditor
            licenseKey="YOUR_LICENSE_KEY"
            apiUrl="https://localhost:3030/social"
            files={selectedFile}
            onClose={handleClose}
            callback={handleExport}
            theme={customTheme}
            showThemeCreator={false}
          />
        </div>
      )}

      {exportedImage && (
        <div className="preview">
          <img src={exportedImage} alt="Edited" />
          <button onClick={handleDownload}>Download</button>
        </div>
      )}
    </div>
  );
}

export default ImageStudio;

Next Steps

Video Editor

Learn how to integrate the VideoEditor component

FAQ

Common issues and troubleshooting
Need help? Contact us at support@distralabs.com