Fields
Image Field
The image field is a convenience wrapper around f.upload() that defaults to image MIME types. It renders an image-optimized upload widget with thumbnail previews. When used with relationTo, it integrates with the upload collection system for managed media. Without relationTo, it stores a plain string reference.
The underlying Convex validator is v.string() for single images or v.array(v.string()) for multiple, wrapped in v.optional() unless marked as required.
Config options
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
required | boolean | false | Makes the field required in the schema and admin UI | |
readOnly | boolean | false | Renders the field as non-editable | |
label | string | function | Field name | Custom label for the admin UI | |
description | string | Help text displayed below the field label | ||
relationTo | string | Upload collection to reference for managed media | ||
accept | string[] | ["image/*"] | Accepted MIME types (e.g., ["image/jpeg", "image/png"]) | |
maxSize | number | Maximum file size in bytes | ||
displayPreview | boolean | true | Show a thumbnail preview of the uploaded image | |
hasMany | boolean | false | Allow multiple image uploads | |
condition | FieldCondition | Condition for showing or hiding this field | ||
sidebar | boolean | false | Place this field in the document sidebar | |
sidebarSection | string | Group under a named sidebar section | ||
listColumn | boolean | false | Show as a default column in list views |
Example usage
import { f, defineVextroCollection } from "vextro";
export const products = defineVextroCollection({
slug: "products",
label: "Products",
collectionType: "content",
tableName: "products",
fields: {
name: f.text({ required: true }),
thumbnail: f.image({
relationTo: "media",
required: true,
label: "Product Image",
accept: ["image/jpeg", "image/png", "image/webp"],
maxSize: 5 * 1024 * 1024,
listColumn: true,
listColumnWidth: "small",
}),
gallery: f.image({
relationTo: "media",
hasMany: true,
label: "Gallery Images",
description: "Additional product photos",
}),
avatar: f.image({
accept: ["image/jpeg", "image/png"],
maxSize: 2 * 1024 * 1024,
label: "Avatar",
description: "Square image, max 2 MB",
}),
},
}); Admin options
The image field displays a thumbnail preview of the uploaded image by default. When relationTo is set, the field integrates with the upload collection, allowing editors to either upload a new image or select from previously uploaded media via a media browser.
When accept is configured, the file input restricts selectable file types. The default is ["image/*"], which accepts all image formats. Narrow this to specific formats like ["image/jpeg", "image/png"] when you need to enforce a particular format.
The maxSize option validates file size client-side before upload. Files exceeding the limit are rejected with an error message.
In list views with listColumn: true, the image renders as a small thumbnail for quick visual identification.
Conditional display
heroImage: f.image({
relationTo: "media",
label: "Hero Image",
condition: { field: "layout", in: ["hero", "featured"] },
description: "Large banner image for hero layouts",
})