Overview
The Image plugin provides a complete solution for adding images to your content. It supports file uploads, URL insertion, image resizing, and various display options.
Installation
npm install @yoopta/image
Basic Usage
import { Image } from '@yoopta/image' ;
const plugins = [
Image ,
// ... other plugins
];
< YooptaEditor editor = { editor } plugins = { plugins } /> ;
Required Configuration You must configure the upload and delete options. Without these options, you’ll see an error when trying to use the Image plugin. // Required when using themes
const plugins = [
Image . extend ({
options: {
upload : async ( file ) => {
// Your upload logic here
return { id: '...' , src: '...' };
},
delete : async ( src ) => {
// Your delete logic here
},
},
}),
];
See the Configuration section below for detailed examples.
Features
File Upload : Upload images from device
URL Insertion : Insert images via URL
Custom Upload Functions : Direct uploads to Cloudinary, S3, Firebase, etc.
Image Resizing : Resize images while maintaining aspect ratio
Size Limits : Set maximum width and height
Object Fit : Control how images fit their container
Image Deletion : Optional deletion handling with custom functions
Responsive : Automatically adapts to screen size
Configuration
The Image plugin supports two approaches for upload and delete operations:
Endpoint-based : Configure an API endpoint and the plugin handles the request
Custom function : Provide your own async function for complete control (useful for direct uploads to Cloudinary, S3, Firebase, etc.)
Endpoint-based Upload (Backend API)
import { Image } from '@yoopta/image' ;
const plugins = [
Image . extend ({
options: {
upload: {
endpoint: '/api/upload' ,
method: 'POST' ,
headers: {
Authorization: `Bearer ${ token } ` ,
},
onSuccess : ( result ) => {
console . log ( 'Upload successful:' , result );
},
onError : ( error ) => {
console . error ( 'Upload failed:' , error );
},
},
delete: {
endpoint: '/api/delete' ,
method: 'DELETE' ,
},
maxSizes: {
maxWidth: 800 ,
maxHeight: 600 ,
},
},
}),
];
Custom Upload Function (Direct to Cloud)
For direct uploads to third-party services like Cloudinary, AWS S3, or Firebase Storage, you can provide a custom async function:
import { Image } from '@yoopta/image' ;
const plugins = [
Image . extend ({
options: {
// Custom upload function
upload : async ( file , onProgress ) => {
const formData = new FormData ();
formData . append ( 'file' , file );
formData . append ( 'upload_preset' , 'your_preset' );
const response = await fetch (
'https://api.cloudinary.com/v1_1/your_cloud/image/upload' ,
{ method: 'POST' , body: formData }
);
const data = await response . json ();
// Return ImageElementProps
return {
id: data . public_id ,
src: data . secure_url ,
sizes: {
width: data . width ,
height: data . height ,
},
};
},
// Custom delete function
delete : async ( src ) => {
// Extract public_id and delete from your service
const publicId = extractPublicId ( src );
await fetch ( `/api/cloudinary-delete/ ${ publicId } ` , { method: 'DELETE' });
},
maxSizes: {
maxWidth: 800 ,
maxHeight: 600 ,
},
},
}),
];
Custom Fetch to Your API
You can also use a custom function to call your own API with fetch:
import { Image } from '@yoopta/image' ;
const plugins = [
Image . extend ({
options: {
upload : async ( file , onProgress ) => {
const formData = new FormData ();
formData . append ( 'file' , file );
const response = await fetch ( '/api/image-kit-upload' , {
method: 'POST' ,
body: formData ,
});
if ( ! response . ok ) {
throw new Error ( 'Upload failed' );
}
const data = await response . json ();
return {
id: data . fileId ,
src: data . url ,
sizes: {
width: data . width ,
height: data . height ,
},
};
},
delete : async ( src ) => {
await fetch ( '/api/image-kit-delete' , {
method: 'DELETE' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({ src }),
});
},
},
}),
];
Options
upload
Can be either an object (endpoint-based) or a function (custom upload):
Endpoint Object
Custom Function
URL endpoint for image upload
method
'POST' | 'PUT' | 'PATCH'
default: "POST"
HTTP method for upload
Custom headers for upload request
Form field name for the file
Maximum file size in bytes
Accepted file types (e.g., “image/png,image/jpeg”)
Callback for upload progress
Callback when upload succeeds
Callback when upload fails
Custom async function for direct uploads to third-party services. Signature: ( file : File , onProgress ?: ( progress : ImageUploadProgress ) => void ) => Promise < ImageElementProps >
Returns ImageElementProps:
id - Unique identifier for the image
src - URL of the uploaded image
sizes - Object with width and height
delete
Can be either an object (endpoint-based) or a function (custom delete):
Endpoint Object
Custom Function
URL endpoint for image deletion
method
'DELETE' | 'PATCH'
default: "DELETE"
HTTP method for deletion
Custom headers for delete request
Custom async function for deleting images from third-party services. Signature: ( src : string ) => Promise < void >
Parameters:
src - The URL/source of the image to delete
Maximum image width in pixels
Maximum image height in pixels
provider
'imgix' | 'cloudinary' | 'akamai'
Image optimization provider
Element Props
Alternative text for accessibility
Responsive image source set
fit
'contain' | 'cover' | 'fill' | null
How the image should fit its container
Image dimensions: { width: number, height: number }
Background color for image container
Commands
import { ImageCommands } from '@yoopta/image' ;
// Update image source
ImageCommands . updateImage ( editor , blockId , {
src: 'https://example.com/image.jpg' ,
alt: 'Description' ,
});
// Delete image
ImageCommands . deleteImage ( editor , blockId );
Your upload endpoint should return:
{
id : string ;
url : string ;
width ?: number ;
height ?: number ;
size ?: number ;
format ?: string ;
}
Custom Rendering
import { Image } from '@yoopta/image' ;
const CustomImage = Image . extend ({
elements: {
image: {
render : ( props ) => {
const { src , alt , sizes , fit } = props . element . props ;
return (
< figure { ... props . attributes } contentEditable = { false } >
< img
src = { src }
alt = { alt }
width = { sizes . width }
height = { sizes . height }
style = { { objectFit: fit } }
loading = "lazy"
/>
{ alt && < figcaption > { alt } </ figcaption > }
{ props . children }
</ figure >
);
},
},
},
});
Parsers
HTML Deserialization
The plugin automatically deserializes <img> tags:
< img src = "image.jpg" alt = "Description" width = "650" height = "500" />
HTML Serialization
< div style = "display: flex; justify-content: center;" >
< img src = "image.jpg" alt = "Description" width = "650" height = "500" />
</ div >
Markdown Serialization

Use Cases
Blog Posts Feature images and inline illustrations
Documentation Screenshots and diagrams
Portfolios Project images and galleries
Product Catalogs Product images with descriptions
Best Practices
Compress and resize images before uploading to reduce load times
Provide descriptive alt text for accessibility
Configure appropriate maxWidth and maxHeight for your design
Enable lazy loading for better performance
Handle upload errors gracefully with user feedback
Hooks
useImageUpload
Supports both endpoint-based and custom function approaches:
Endpoint-based
Custom Function
import { useImageUpload } from '@yoopta/image' ;
const { upload , loading , progress , error } = useImageUpload ({
endpoint: '/api/upload' ,
onSuccess : ( result ) => {
console . log ( 'Uploaded:' , result . url );
},
});
// Upload a file
const handleUpload = async ( file : File ) => {
const result = await upload ( file );
};
import { useImageUpload } from '@yoopta/image' ;
const { upload , loading , progress , error } = useImageUpload (
async ( file , onProgress ) => {
const formData = new FormData ();
formData . append ( 'file' , file );
const response = await fetch ( 'https://api.cloudinary.com/v1_1/cloud/upload' , {
method: 'POST' ,
body: formData ,
});
const data = await response . json ();
return {
id: data . public_id ,
src: data . secure_url ,
sizes: { width: data . width , height: data . height },
};
}
);
const handleUpload = async ( file : File ) => {
const result = await upload ( file );
};
useImageDelete
Supports both endpoint-based and custom function approaches:
Endpoint-based
Custom Function
import { useImageDelete } from '@yoopta/image' ;
const { deleteImage , loading , error } = useImageDelete ({
endpoint: '/api/delete' ,
});
import { useImageDelete } from '@yoopta/image' ;
const { deleteImage , loading , error } = useImageDelete (
async ( src ) => {
await fetch ( '/api/delete' , {
method: 'DELETE' ,
body: JSON . stringify ({ src }),
});
}
);
Troubleshooting
Error: Upload options are not configured
Error: Delete options are not configured
Error: Missing 'endpoint' in upload/delete options
This error occurs when using endpoint-based configuration without providing the endpoint URL. Solution: Make sure to include the endpoint property:Image . extend ({
options: {
upload: {
endpoint: '/api/upload-image' , // Required!
},
delete: {
endpoint: '/api/delete-image' , // Required!
},
},
})