Skip to content

Image Plugin

The ImagePlugin adds image block support with a toolbar button that opens an upload/URL popup, drag-and-drop file handling, and alignment options.

import { ImagePlugin } from '@notectl/core/plugins/image';
new ImagePlugin()
// or with custom config:
new ImagePlugin({
maxFileSize: 10 * 1024 * 1024, // 10 MB
acceptedTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/svg+xml'],
maxWidth: 800,
resizable: true,
})
interface ImagePluginConfig {
/** Maximum width in pixels for inserted images. */
readonly maxWidth: number;
/** Maximum file size in bytes. */
readonly maxFileSize: number;
/** Accepted MIME types for file upload. */
readonly acceptedTypes: readonly string[];
/** Enable resize handles on images. */
readonly resizable: boolean;
/** Pixels to grow/shrink per small resize step. @default 10 */
readonly resizeStep?: number;
/** Pixels to grow/shrink per large resize step. @default 50 */
readonly resizeStepLarge?: number;
/** Customize keyboard bindings for image resize actions. */
readonly keymap?: ImageKeymap;
/** Locale override for user-facing strings. */
readonly locale?: ImageLocale;
}

Defaults: maxWidth: 800, maxFileSize: 10 MB, acceptedTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/svg+xml'], resizable: true, resizeStep: 10, resizeStepLarge: 50.

Customize or disable individual keyboard resize bindings. Set a slot to null to disable it.

interface ImageKeymap {
readonly growWidth?: string | null;
readonly shrinkWidth?: string | null;
readonly growWidthLarge?: string | null;
readonly shrinkWidthLarge?: string | null;
readonly resetSize?: string | null;
}
Command Description Returns
insertImage Open the image insertion popup boolean
removeImage Remove the currently selected image boolean
resizeImageGrow Increase width by resizeStep (default 10px) boolean
resizeImageShrink Decrease width by resizeStep (default 10px) boolean
resizeImageGrowLarge Increase width by resizeStepLarge (default 50px) boolean
resizeImageShrinkLarge Decrease width by resizeStepLarge (default 50px) boolean
resetImageSize Reset image to natural size boolean
editor.executeCommand('insertImage');
editor.executeCommand('removeImage');
editor.executeCommand('resizeImageGrow');

When an image is selected (node selection):

Shortcut Command Description
Mod-Shift-ArrowRight resizeImageGrow Grow width by small step (10px)
Mod-Shift-ArrowLeft resizeImageShrink Shrink width by small step (10px)
Mod-Shift-Alt-ArrowRight resizeImageGrowLarge Grow width by large step (50px)
Mod-Shift-Alt-ArrowLeft resizeImageShrinkLarge Shrink width by large step (50px)
Mod-Shift-0 resetImageSize Reset to natural size

All shortcuts are customizable via the keymap config option.

The image button opens a custom popup with:

  • A file upload input accepting the configured file types
  • A URL input field for remote images
  • Upload state feedback during file processing
Type HTML Tag Attributes Description
image <figure><img></figure> src, alt, align, width?, height? Image block (void)

The image block is a void block — it is not editable but can be selected (node selection). The align attribute supports 'start', 'center', and 'end' with corresponding CSS classes. Legacy values (left/right) are accepted during parsing for backward compatibility.

Register a custom upload service to handle file uploads:

import { IMAGE_UPLOAD_SERVICE } from '@notectl/core/plugins/image';
const uploadService: ImageUploadService = {
upload: async (file: File) => {
const formData = new FormData();
formData.append('file', file);
const response = await fetch('/api/upload', { method: 'POST', body: formData });
const data = await response.json();
return { url: data.url };
},
};
context.registerService(IMAGE_UPLOAD_SERVICE, uploadService);

Without a registered upload service, images are inserted as blob URLs (suitable for development).

The plugin registers a file handler for image/* MIME types. This enables:

  • Drag-and-drop: Drop image files directly into the editor
  • Paste: Paste images from the clipboard

The image block uses a custom NodeView for:

  • Upload progress state visualization
  • Blob URL lifecycle management (automatic cleanup on destroy)
  • Responsive image sizing with width/height preservation
  • When an image is selected, a screen reader announcement is made including alt text, pixel dimensions, and available resize shortcuts
  • After each resize operation, the new dimensions are announced
  • The image <figure> has a localized aria-label with alt text and dimensions
  • All resize shortcuts work via keyboard — no mouse required