GitHub - blade47/editorjs-image: Image Block for Editor.js

Image Tool (Enhanced Fork)

Enhanced Image Block for Editor.js with interactive resizing, modern UI, and improved performance.

πŸŽ₯ Demo

Project Demo

Interactive resizing, modern UI, and smooth animations in action

πŸš€ What's New in This Fork

This is an enhanced fork of the official @editorjs/image tool with significant changes and a simplified, focused feature set.

✨ Major Enhancements

  • 🎨 Interactive Image Resizing - Drag handles on left/right sides to resize images dynamically
  • 🎬 Enhanced Video Support - Full support for MP4 videos with controls, autoplay, and loop
  • πŸ’Ž Modern UI Design - Complete visual overhaul with smooth animations, gradients, and improved aesthetics
  • ⚑ Performance Optimizations - Lazy loading, async image decoding, and improved rendering performance
  • 🎯 Better Captions - Centered captions that auto-hide when empty in read-only mode
  • πŸ›‘οΈ Improved Reliability - Defensive dimension handling prevents data corruption
  • πŸ“ Dimension Persistence - Remembers exact pixel dimensions set by user
  • 🎭 Fade-in Animations - Smooth image loading transitions with opacity effects

πŸ”„ Simplified Architecture

This fork removes the tunes/settings UI (border, background, stretch options) to provide a cleaner, more focused editing experience centered around the core functionality: uploading, displaying, and resizing images/videos.

Features

Core Features

  • βœ… Upload files from device
  • βœ… Paste copied content from the web
  • βœ… Drag-and-drop image uploads
  • βœ… Paste files and screenshots from Clipboard
  • βœ… Caption support with auto-hide in read-only mode

Enhanced Features (This Fork)

  • ✨ Interactive resize handles - Drag left or right edges to resize images and videos
  • ✨ Video element support - Display MP4 videos as embedded players
  • ✨ Modern preloader - Animated spinner with loading text
  • ✨ Smooth transitions - Fade-in effects with cubic-bezier easing
  • ✨ Responsive design - Mobile-optimized with breakpoints at 768px and 800px, max-width: 100% prevents overflow
  • ✨ Dimension safety - Never saves corrupted 0Γ—0 dimensions
  • ✨ Aspect ratio preservation - Automatic aspect ratio maintenance during resize
  • ✨ Dimension persistence - Remembers exact pixel sizes set by user

Notes

This Tool requires server-side implementation for file uploading. See backend response format for more details.

Video files are displayed using the <video> element with controls, autoplay, loop, and muted attributes for a GIF-like experience.

Installation

Get the package

npm install @blade47/editorjs-image
# or
yarn add @blade47/editorjs-image

Include module at your application

import ImageTool from '@blade47/editorjs-image';

Usage

Add a new Tool to the tools property of the Editor.js initial config.

import ImageTool from '@blade47/editorjs-image';

// or if you inject ImageTool via standalone script
const ImageTool = window.ImageTool;

var editor = EditorJS({
  ...

  tools: {
    ...
    image: {
      class: ImageTool,
      config: {
        endpoints: {
          byFile: 'http://localhost:8008/uploadFile', // Your backend file uploader endpoint
          byUrl: 'http://localhost:8008/fetchUrl', // Your endpoint that provides uploading by Url
        }
      }
    }
  }

  ...
});

Config Params

Image Tool supports these configuration parameters:

Field Type Description
endpoints {byFile: string, byUrl: string} Required if no custom uploader. Endpoints for file uploading.
Contains 2 fields:
byFile - for file uploading
byUrl - for uploading by URL
field string (default: image) Name of uploaded image field in POST request
types string (default: image/*) Mime-types of files that can be accepted with file selection. Use image/*,video/mp4 for video support.
additionalRequestData object Object with any data you want to send with uploading requests
additionalRequestHeaders object Object with any custom headers which will be added to request. See example
captionPlaceholder string (default: Enter a caption) Placeholder for caption input
buttonContent string Allows to override HTML content of Β«Select fileΒ» button
uploader {{uploadByFile: function, uploadByUrl: function}} Optional custom uploading methods. See details below.
actions array Array with custom actions to show in the tool's settings menu. See details below.
showCaption boolean (default: true) Show or hide the caption field

Note that if you don't implement your custom uploader methods, the endpoints param is required.

Custom Actions

You can add custom action buttons to the tool's settings menu:

image: {
  class: ImageTool,
  config: {
    endpoints: {
      byFile: 'http://localhost:8008/uploadFile',
    },
    actions: [
      {
        name: 'download',
        icon: '<svg>...</svg>',
        title: 'Download Image',
        toggle: false,
        action: () => {
          // Your custom action logic
          console.log('Download clicked');
        }
      }
    ]
  }
}

Output Data

This Tool returns data with following format

Field Type Description
file object Uploaded file data. Any data got from backend uploader. Always contains the url property
caption string Image's caption
width string Image width in pixels (preserved from user resizing)
height string Image height in pixels (preserved from user resizing)
{
    "type": "image",
    "data": {
        "file": {
            "url": "https://www.tesla.com/tesla_theme/assets/img/_vehicle_redesign/roadster_and_semi/roadster/hero.jpg"
        },
        "caption": "Roadster // tesla.com",
        "width": "800",
        "height": "450"
    }
}

Notes:

  • Unlike the original tool, this fork does not include withBorder, withBackground, or stretched fields as the tunes/settings UI has been removed for a cleaner, more focused experience.
  • Dimension storage: Width and height are stored in pixels, preserving the exact size the user set when resizing. Combined with CSS max-width: 100%, images automatically scale down on smaller screens while maintaining the user's intended size on larger displays.

Backend Response Format

This Tool works by one of the following schemes:

  1. Uploading files from the device
  2. Uploading by URL (handle image-like URL's pasting)
  3. Uploading by drag-n-drop file
  4. Uploading by pasting from Clipboard

Uploading Files from Device

Scenario:

  1. User selects file from the device
  2. Tool sends it to your backend (on config.endpoints.byFile route)
  3. Your backend should save file and return file data with JSON at specified format
  4. Image tool shows saved image and stores server answer

So, you can implement backend for file saving by your own way. It is a specific and trivial task depending on your environment and stack.

The tool executes the request as multipart/form-data, with the key as the value of field in configuration.

The response of your uploader should cover the following format:

{
    "success": 1,
    "file": {
        "url": "https://www.tesla.com/tesla_theme/assets/img/_vehicle_redesign/roadster_and_semi/roadster/hero.jpg",
        // ... and any additional fields you want to store, such as width, height, color, extension, etc
    }
}

success - uploading status. 1 for successful, 0 for failed

file - uploaded file data. Must contain a url field with full public path to the uploaded image. Also, can contain any additional fields you want to store. For example, width, height, id etc. All additional fields will be saved at the file object of output data.

Uploading by Pasted URL

Scenario:

  1. User pastes a URL of the image file to the Editor
  2. Editor passes pasted string to the Image Tool
  3. Tool sends it to your backend (on config.endpoints.byUrl route) via 'url' in request body
  4. Your backend should accept URL, download and save the original file by passed URL and return file data with JSON at specified format
  5. Image tool shows saved image and stores server answer

The tool executes the request as application/json with the following request body:

{
  "url": "<pasted URL from the user>",
  "additionalRequestData": "<additional request data from configuration>"
}

Response of your uploader should be at the same format as described at Β«Uploading files from deviceΒ» section.

Uploading by Drag-n-Drop or from Clipboard

Your backend will accept file as FormData object in field name, specified by config.field (by default, Β«imageΒ»). You should save it and return the same response format as described above.

Providing Custom Uploading Methods

As mentioned at the Config Params section, you have an ability to provide own custom uploading methods. It is quite simple: implement uploadByFile and uploadByUrl methods and pass them via uploader config param. Both methods must return a Promise that resolves with response in a format that described at the backend response format section.

Method Arguments Return value Description
uploadByFile File {Promise.<{success, file: {url}}>} Upload file to the server and return uploaded image data
uploadByUrl string {Promise.<{success, file: {url}}>} Send URL-string to the server, that should load image by this URL and return uploaded image data

Example:

import ImageTool from '@blade47/editorjs-image';

var editor = EditorJS({
  ...

  tools: {
    ...
    image: {
      class: ImageTool,
      config: {
        /**
         * Custom uploader
         */
        uploader: {
          /**
           * Upload file to the server and return uploaded image data
           * @param {File} file - file selected from the device or pasted by drag-n-drop
           * @return {Promise.<{success, file: {url}}>}
           */
          uploadByFile(file) {
            // your own uploading logic here
            return MyAjax.upload(file).then(() => {
              return {
                success: 1,
                file: {
                  url: 'https://codex.so/upload/redactor_images/o_80beea670e49f04931ce9e3b2122ac70.jpg',
                  // any other image data you want to store, such as width, height, color, extension, etc
                }
              };
            });
          },

          /**
           * Send URL-string to the server. Backend should load image by this URL and return uploaded image data
           * @param {string} url - pasted image URL
           * @return {Promise.<{success, file: {url}}>}
           */
          uploadByUrl(url) {
            // your ajax request for uploading
            return MyAjax.upload(url).then(() => {
              return {
                success: 1,
                file: {
                  url: 'https://codex.so/upload/redactor_images/o_e48549d1855c7fc1807308dd14990126.jpg',
                  // any other image data you want to store, such as width, height, color, extension, etc
                }
              }
            })
          }
        }
      }
    }
  }

  ...
});

🎨 Enhanced Features Guide

Interactive Image Resizing

Images and videos can be resized by dragging the handles that appear on hover:

  • Left handle - Resize from the left edge
  • Right handle - Resize from the right edge
  • Aspect ratio - Automatically maintained during resize
  • Minimum size - Images cannot be resized below 30px width
  • Mobile - Resize handles hidden on screens < 800px for better mobile experience

The resized dimensions are automatically saved and restored when the content is loaded again.

Video Support

To enable video uploads, configure the types parameter:

image: {
  class: ImageTool,
  config: {
    types: 'image/*,video/mp4',
    endpoints: {
      byFile: 'http://localhost:8008/uploadFile',
    }
  }
}

Videos are displayed with:

  • βœ… Autoplay (muted for autoplay compliance)
  • βœ… Loop playback (GIF-like behavior)
  • βœ… Playback controls
  • βœ… Inline playback (mobile-friendly)
  • βœ… Same resize capabilities as images

Modern UI Enhancements

This fork includes a completely redesigned interface with:

  • Gradient accents - Modern blue gradients (#0066ff to #0052cc) on interactive elements
  • Smooth animations - Fade-in effects and cubic-bezier easing for professional feel
  • Enhanced preloader - Animated spinner with background gradient and loading text
  • Better spacing - Improved padding and margins throughout
  • Rounded corners - Modern 12px border radius (8px on mobile)
  • Shadow effects - Subtle shadows on hover for depth perception
  • Centered captions - Professional center-aligned captions
  • Responsive typography - Optimized font sizes for mobile (14px β†’ 13px)

CSS Customization

The tool uses CSS custom properties for easy theming:

.image-tool {
  --bg-color: #f7f9fc;
  --front-color: #0066ff;
  --border-color: #e1e8f0;
  --text-primary: #1a1a1a;
  --text-secondary: #6b7280;
}

πŸ”§ Development

Testing Locally

A development server is included for testing uploads:

This exposes port 8008 with two endpoints:

  • http://localhost:8008/uploadFile - File upload endpoint
  • http://localhost:8008/fetchUrl - URL fetch endpoint

Files are saved to dev/.tmp/ directory.

Configure your tool to use these endpoints during development:

config: {
  endpoints: {
    byFile: 'http://localhost:8008/uploadFile',
    byUrl: 'http://localhost:8008/fetchUrl',
  }
}

Build

Outputs:

  • dist/image.umd.js - UMD bundle for <script> tags and CommonJS
  • dist/image.mjs - ES module for modern imports
  • dist/index.d.ts - TypeScript type declarations

Linting

npm run lint          # Check for errors
npm run lint:errors   # Show errors only (quiet)
npm run lint:fix      # Auto-fix issues

πŸ“¦ Package Information

🀝 Contributing

This is a fork maintained separately from the original Editor.js Image tool.

Original Tool: editor-js/image This Fork: blade47/editorjs-image

πŸ“ Changelog

v3.0.6 (2025-10-23)

  • πŸ›‘οΈ Fixed critical dimension corruption bug - prevents saving 0Γ—0 dimensions
  • πŸ”§ Fixed ESLint configuration issues (removed deprecated rules, resolved version conflicts)
  • πŸ“ Improved code quality and TypeScript type safety
  • ✨ Changed async onPaste to sync for better Editor.js compatibility
  • πŸ“ Dimensions stored in pixels with CSS max-width: 100% for responsive behavior

v3.0.3 (2025-06)

  • ✨ Added interactive image/video resizing with drag handles
  • 🎨 Complete UI/UX overhaul with modern design system
  • ⚑ Performance improvements (lazy loading, async decoding)
  • 🎬 Enhanced video support with controls and autoplay
  • πŸ“ Dimension persistence and restoration
  • 🎯 Improved caption handling (centered, auto-hide in read-only)
  • πŸ—‘οΈ Removed tunes/settings UI (border, background, stretch) for simpler interface

Earlier versions

  • Added height input field
  • Small refactoring and code quality improvements
  • Video controls support
  • Caption styling improvements
  • Development dependency updates

πŸ“„ License

MIT

πŸ™ Credits