Image field

A form field that holds one image: pick it from the library or drop a file, preview, replace, remove, crop to a ratio (non-destructive or as a new copy), set a focal point and a per-use alt text. Warns about missing alt text and low resolution. For featured images, social cards, logos, profile photos and block props.

Media picker · Image cropper (react-easy-crop) · own focal-point control media/image-field.tsx, media/focal-point.tsx, media/image-cropper.tsx, media/media-picker.tsxtheme · material · accent · density · font

Alt textWhite villa with a pool terrace at dusk

Shown on the blog index and in link previews.

Installation

$ pnpm add @vamos-ui/react

The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";

Usage

import { ImageField } from "@vamos-ui/react/media";

<Field label="Featured image">
  <ImageField aspect="16/9" recommended={{ width: 1200, height: 630 }} value={cover} onChange={setCover} />
</Field>

The empty state is a real button (and a drop target); the filled preview is the Replace button and Remove is separate, both labelled. The chosen alt text is shown under the preview.

The focal marker is a focusable 2-D control: aria-roledescription “focal point”, aria-valuetext “horizontal 62%, vertical 40%”; arrows step 1%, Shift + arrows 10%, Home centres.

Save as copy needs a same-origin or CORS-enabled image; otherwise the dialog explains that the image must be uploaded to the library first.

Examples

Round avatar (HR profile)

shape="round" + size="sm" (96px) + layout="inline"; crop locks to 1:1.

Selin Kaya

Alt textSelin Kaya, Head of Sales

New hire

Social image with a low-res warning

recommended={{ width: 1200, height: 630 }} warns below that size; the crop preset named og is stored as asset.crops.og.

Alt textLaptop showing a sales dashboard

Low resolution: 640 × 360 px. Recommended at least 1,200 × 630.

Recommended 1,200 × 630 px or larger

Used by LinkedIn, X and WhatsApp previews.

Focal point

FocalPointPicker on its own: drag, or arrows (Shift for 10%), with live 1:1, 16:9 and 4:5 previews.

Click or drag on the image, or use the arrow keys (Shift for bigger steps), to mark the part that must stay in view when the image is cropped.

focalPoint = {"x":0.62,"y":0.48}

Crop modes

metadata keeps the file and stores a rect for the loader; copy uploads a cropped file.

Metadata (non-destructive)

Alt textRenovated kitchen with a marble island

crop: none
Save as copy

Alt textDining room with pendant lights and wooden tables

file: bistro-dining-room.jpg

In a form with validation (CRM)

Field passes label, hint, error and required; name posts the asset id.

Recommended 400 × 400 px or larger

Square, at least 400 × 400 px.

API

ImageField

PropTypeDefault
value / defaultValue / onChange
{ asset, alt?, focal?, crop? } — alt and focal override the asset per use; crop is a name or a rect.
ImageFieldValue | null—
aspect
Preview ratio and default crop ratio.
ImageAspect ("16/9", "1/1", "1.91/1", number…)"16/9" ("1/1" round)
cropPresets
Ratio buttons in the crop dialog; name stores asset.crops[name].
{ label; value: number; name? }[]—
recommended
Shows a hint, and a warning when the image is smaller.
{ width; height }—
shape
round for avatars.
"rect" | "round""rect"
size
96px avatar · card (22rem) · container width.
"sm" | "md" | "full""md"
layout
inline puts actions and alt text beside the preview.
"stacked" | "inline""stacked"
focal
Focal point tool.
booleantrue (rect)
crop
true offers both modes when the adapter can edit (else copy).
boolean | "metadata" | "copy"true
requireAlt
The picker asks for alt text; the field warns while it is missing.
booleanfalse
accept
Picker filter and drop restriction.
string"image/*"
disabled / readOnly / required / invalid
Also read from a surrounding Field.
boolean—
name
Hidden input with the asset id for native forms.
string—
adapter
Default: MediaProvider.
MediaAdapter—
labels
Built-in strings (dictionary namespace imageField).
Partial<ImageFieldLabels>—

FocalPointPicker

PropTypeDefault
src
The image.
string | MediaAsset—
value / defaultValue / onValueChange
0..1 in image space (not mirrored in RTL).
{ x: number; y: number }—
onValueCommit
Once per drag or key press (autosave).
(point) => void—
previews
Live crop previews.
false | ("1/1" | "16/9" | "4/5" | "4/3" | "1.91/1" | "3/2")[]["1/1","16/9","4/5"]
maxHeight
Image stage height.
number | string"20rem"
disabled / labels
Dictionary namespace focalPoint.
boolean · Partial<FocalPointLabels>—