Skip to content
FrameworkJavaScript

Image block: uploads, captions, and resizing

Embed an image by URL, by upload, or by pasting a file.

Import

TypeScript
import { Image } from '@bloklabs/core/tools';

Configuration

OptionTypeDefaultDescription
uploaderImageUploaderundefined

Consumer-supplied uploader with optional uploadByFile(file, ctx) and uploadByUrl(url, ctx) methods, each resolving to { url, fileName? }. When omitted, images fall back to a local blob URL (uploadByFile) or the pasted URL (uploadByUrl).

typesstring[]['image/*']

Accepted MIME allowlist. Entries may be exact (image/png) or family wildcards (image/*). Defaults to any image type.

maxSizeMaxSizeConfig30 MiB

Max upload size. A number caps every type, in bytes. An object caps each MIME type, with '*' as the fallback. Pass Infinity for unlimited.

onUploadErrorUploadErrorHandlerundefined

Called when an upload fails. It receives { code, tool, message, file?, url?, size?, maxSize?, cause }.

  • Return nothing: the block shows its own message.
  • Return a string: the block shows it instead.
  • Return false: the block goes back to its empty state with no error, so you can show a toast.

A rejection from your own uploader arrives as UPLOAD_FAILED. The original error is in cause.

sources'upload' | 'url' | 'both''both'

Restrict how an image may be added: file upload only, URL only, or both.

convertGifToVideobooleantrue

Auto-convert animated GIFs to a looping WebM video block on insert. It only applies when a video tool is registered. GIFs stay image blocks without one. Set false to always keep GIFs as image blocks.

captionPlaceholderstring"Write a caption…"

Placeholder text shown in the caption field.

compressboolean | ImageCompressionConfigtrue

Re-encode uploaded images before they reach the uploader. It is on by default in a deliberately safe mode: the same format, quality 0.92, and the original dimensions. The result is only used when it saves at least 10%, otherwise the original bytes are uploaded untouched.

Pass an object to opt into smaller output. The keys are format, fallbackFormat, quality, maxWidth / maxHeight, minSize, minSavings and transform(file).

  • format takes 'original' | 'jpeg' | 'webp' | 'avif' | 'auto'.
  • fallbackFormat is the format to try when the browser cannot encode format, before falling back to the source format.
    • So { format: 'avif', fallbackFormat: 'webp' } uploads AVIF where the browser can produce it, and WebP everywhere else.
  • quality runs from 0 to 1.
  • minSize skips files below it, and defaults to 100 KiB.
  • minSavings defaults to 0.1.
  • transform(file) plugs in your own encoder.

Set false to upload the exact original bytes. Compression never breaks an upload. When it cannot help, the original is used.

reloadAttemptsnumber5

How many times a rendered image silently re-fetches its src after a load error before showing the broken-image state. Set 0 to disable auto-retry.

filtersArray<ImageFilterPreset | ImageFilterDefinition>every built-in

The looks the image editor's Filters tab offers, in order. Original always comes first.

  • A string picks a built-in, such as 'vivid', 'noir' or 'film'. There are 23.
  • An object { name, title, css } adds your own look. name is saved in filter, title is the label, and css is a CSS filter value.
    • Only brightness, contrast, saturate, grayscale, sepia, invert and hue-rotate are kept.
    • Reusing a built-in name retunes that built-in.
  • [] hides the Filters tab.

A built-in you leave out still renders on images that already use it. A saved name this editor does not know renders unfiltered and is kept on save.

Save Data

TypeScript
interface ImageData {
  url: string;             // Image source URL — http(s) or blob:
  caption?: string;        // Plain-text caption
  width?: number;          // Width as percent of container, 10–100 (default 100)
  alignment?: 'left' | 'center' | 'right';
  size?: 'sm' | 'md' | 'lg' | 'full'; // Discrete size preset; overrides width when set
  frame?: 'none' | 'border' | 'shadow'; // Decorative frame treatment (default 'none')
  rounded?: boolean;       // Rounded corners (default true)
  captionVisible?: boolean; // Caption visible in the rendered state (default true)
  crop?: ImageCrop;        // Non-destructive crop rectangle, in the turned image's box
  rotation?: 0 | 90 | 180 | 270; // Clockwise quarter turn (omitted for 0)
  flipX?: boolean;         // Mirrored left to right, before rotation
  straighten?: number;     // Fine turn in degrees, -45 to 45, after rotation
  filter?: ImageFilterPreset | string; // A built-in look or a host filter name (omitted for 'none')
  filterStrength?: number; // How strongly filter applies, 0 to 100 (omitted for 100)
  adjust?: { brightness?: number; contrast?: number; saturation?: number }; // Each -100 to 100
  markup?: ImageMarkup[];  // Drawings, shapes and text over the image, back to front
  alt?: string;            // Alt text for screen readers
  fileName?: string;       // Original filename, when known
  naturalWidth?: number;   // Intrinsic pixel width of the source (cached)
  naturalHeight?: number;  // Intrinsic pixel height of the source (cached)
  variants?: { url: string; mimeType: string }[]; // Other formats, best first
}
JSON
{
  "id": "img001",
  "type": "image",
  "data": {
    "url": "https://example.com/image.png",
    "caption": "A cat",
    "alt": "A cat",
    "alignment": "center"
  }
}

Usage Example

TypeScript
import { Blok } from '@bloklabs/core';
import { Image } from '@bloklabs/core/tools';

const editor = new Blok({
  holder: 'editor',
  tools: {
    image: {
      class: Image,
      config: {
        uploader: {
          async uploadByFile(file) {
            const url = await myUpload(file);
            return { url, fileName: file.name };
          },
        },
      },
    },
  },
});