editor-js / editor-js/image

Lazy loading images

Open
#300 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
285
Forks
307
PR merge metrics
No merged PRs in 30d

Description

# Feature Request: Add `lazyLoading` config option to defer image fetching

## Description

The `@editorjs/image` plugin currently loads **all images eagerly** at editor initialization time, regardless of their position in the document. There is no built-in way to defer image loading for off-screen blocks.

This becomes a significant problem when using a **custom uploader backed by a private/authenticated endpoint** — every image URL in the document triggers an immediate network request the moment the editor renders, even for images far below the fold that the user may never reach.

---

## Problem

When an Editor.js document contains many image blocks (e.g. a long article or report), all images are fetched simultaneously on load. The current implementation unconditionally assigns `src` at render time:

```ts
// src/ui.ts (current behavior)
const attributes: { [key: string]: string | boolean } = {
src: url, // always set immediately
};
```

### Impact

- **Unnecessary backend requests** — private image endpoints are called for every image in the document, even those never seen by the user.
- **Performance degradation** — large documents with many images cause a burst of parallel requests on load, slowing down the initial render.
- **Increased server costs** — authenticated or CDN-backed image servers are hit unnecessarily.
- **Poor UX on slow connections** — bandwidth is consumed by off-screen images instead of prioritizing visible content.

---

## Steps to Reproduce

1. Configure `@editorjs/image` with a custom uploader pointing to a private backend.
2. Load a document with 10+ image blocks.
3. Open the Network tab in DevTools.
4. Observe that **all image requests fire simultaneously** on editor load, including images far below the viewport.

---

## Proposed Solution

Add an optional `lazyLoading` boolean to the plugin config. When enabled, the `src` attribute should be withheld until the image container approaches the viewport, using an `IntersectionObserver`.

### Config API

```ts
// ImageConfig (types.ts)
interface ImageConfig {
// ...existing options

/**
* Enables lazy loading for images.
* When true, images are only fetched when they approach the viewport.
* @default false
*/
lazyLoading?: boolean;
}
```

### Usage

```ts
const editor = new EditorJS({
tools: {
image: {
class: ImageTool,
config: {
uploader: { /* your custom uploader */ },
lazyLoading: true, // 👈
},
},
},
});
```

## Alternatives Considered

- **Native `loading="lazy"` attribute** — simpler, but the image's **_load event_** is never triggered because we have the preloader container.

---

## Additional Context

- Affects most severely: documents with many images, private/authenticated backends, slow network connections.
- `IntersectionObserver` is [[supported in all modern browsers](https://caniuse.com/intersectionobserver)](https://caniuse.com/intersectionobserver).
- This change is fully **backwards compatible** — `lazyLoading` defaults to `false`.

---

## Are you willing to contribute a PR?

Yes, a working implementation has been prototyped and validated locally. Happy to submit a pull request if the maintainers are open to this feature.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.