Image
Image upload with drag-and-drop, alt text, and asset browser.
The image type handles image uploads. It provides a drag-and-drop upload zone, image preview, alt text editing, and an asset browser for reusing previously uploaded images.
Definition
import type { ImageField } from '@aphexcms/cms-core';{
name: 'cover',
type: 'image',
title: 'Cover Image'
}Properties
| Property | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Field identifier. |
type | 'image' | Yes | Must be 'image'. |
title | string | Yes | Label shown in the admin UI. |
description | string | No | Help text shown below the label. |
accept | string | string[] | No | Allowed MIME types, wildcards, or extensions. Defaults to 'image/*'. |
private | boolean | No | If true, the asset CDN route requires an authenticated session with access to its org. |
initialValue | string | () => string | Promise<string> | No | Default value. |
validation | (Rule) => Rule | No | Validation rules. |
The type definition also includes hotspot, metadata, and fields properties. These are reserved for future use and are not yet implemented.
Stored Data
Images are stored as a reference to an asset record:
{
_type: 'image',
asset: {
_type: 'reference',
_ref: 'asset-id'
}
}The referenced asset stores the actual file metadata (URL, filename, dimensions, alt text, etc.) separately in the assets table. To turn asset._ref into a usable URL when rendering, see Frontend → resolve asset refs to URLs.
Examples
Basic image
{
name: 'photo',
type: 'image',
title: 'Photo',
validation: (Rule) => Rule.required()
}Restricted file types
The same MIME type, wildcard, and extension syntax described for file fields is available here. A comma-separated string and an array are equivalent:
{
name: 'logo',
type: 'image',
title: 'Logo',
accept: ['image/svg+xml', 'image/png', '.png'],
description: 'SVG or PNG only.'
}accept can only narrow the installation-wide allow-list, never widen it. If a type isn't in
storage.allowedMimeTypes — or the built-in default when you haven't
set one — a field listing it still rejects the upload.
SVG is in that default list, because logos and icons overwhelmingly are SVG. It is safe
there only because of how it's served: every image/svg+xml response from
/media/{id}/{filename} carries Content-Disposition: attachment and a
default-src 'none'; sandbox CSP. An <img src="..."> renders it normally — scripts never
execute in an image context — but a browser cannot be navigated to it as a document, which
is what would otherwise make an uploaded SVG stored XSS on your own origin.
Private image
Mark a field private when the image should only be served to authenticated members of the owning organization:
{
name: 'idScan',
type: 'image',
title: 'ID Scan',
private: true
}Requests to /media/[id]/[filename] for a private asset return 401 unless the request carries a
valid session, or a signed URL — the way to show a private image to a
visitor with no admin account.
Privacy is resolved from the field the asset was uploaded into. An image uploaded through the media library and then referenced here stays public; upload it through this field instead.
In a document
const product = defineType({
type: 'document',
name: 'product',
title: 'Product',
fields: [
{
name: 'name',
type: 'string',
title: 'Name',
validation: (Rule) => Rule.required()
},
{
name: 'image',
type: 'image',
title: 'Product Image'
},
{
name: 'price',
type: 'number',
title: 'Price',
validation: (Rule) => Rule.required().positive()
}
]
});Validation
Available rules: required(), custom(fn), error(msg), warning(msg), info(msg)
Last updated on