Overview

Images Schema

s.images()

An image gallery: a collection of images that is the whole module. Where s.image() defines a single field, s.images() defines a module that holds many images at once, keyed by their file path. Editors get one place to upload to, and fields elsewhere pick from it with s.image(galleryModule).

The content is a record: each key is the path of a file in the gallery directory, and each value is the metadata Val read off that file (width, height, mimeType) plus the alt text someone typed. You do not write these entries by hand - they appear when a file is uploaded through Val Studio, the CLI or the VS Code extension.

Galleries do not show up in the Explorer file tree in Val Studio. They are listed under Media, labelled by their directory.

Options:
directory: "/public" | `/public/${string}`

Required. Where the files in this gallery are stored. Must start with /public. Two galleries may not claim the same directory.

s.images({ directory: "/public/val/images" })
accept: `image/${string}`

Which image types the gallery accepts. Unlike s.image(), this must be a mime type starting with image/ - for example image/png, image/webp or image/*. Extension-style unique file type specifiers such as .png do not typecheck here. Defaults to image/*.

s.images({ directory: "/public/val/images", accept: "image/webp" })
alt: s.string() | s.string().nullable() | s.record(s.string(), s.string())

The schema for each entry's alt text. Defaults to s.string().nullable(), which makes alt text optional. Use s.string() to require it, or a record to make it per locale.

NOTE: requiring alt text means an uploaded image is not publishable until someone types it, since upload sets alt to null.

s.images({ directory: "/public/val/images", alt: s.string().minLength(4) })
encode: false | { type: "webp"; quality?: number; maxWidth?: number; maxHeight?: number }

Re-encode uploads in the browser before they are uploaded. Off unless set. Fields backed by this gallery inherit it. The original bytes are kept if the converted file would be bigger and no downscale was needed, and SVG, GIF and AVIF are never converted.

s.images({ directory: "/public/val/images", encode: { type: "webp" } })
Methods:
.remote: method

Store the files of this gallery on Val's remote server instead of in your git repository. See the remote files guide.

s.images({ directory: "/public/val/images" }).remote()
Examples:
Defining a gallery
content/gallery.val.ts
import { c, s } from "../val.config";

// A gallery is the entire module - the schema is not wrapped in an object
export default c.define(
  "/content/gallery.val.ts",
  s.images({ directory: "/public/val/images" }),
  {
    // Entries are added when you upload a file. They are keyed by file path.
    "/public/val/images/hero_a1b2c.png": {
      width: 1920,
      height: 1080,
      mimeType: "image/png",
      alt: "Hero image",
    },
  },
);
Picking an image from the gallery
content/page.val.ts
import { c, s } from "../val.config";
import galleryVal from "./gallery.val";

export default c.define(
  "/content/page.val.ts",
  s.object({
    title: s.string(),
    // Pass the gallery module to s.image() to pick from it
    hero: s.image(galleryVal),
  }),
  {
    title: "Front page",
    // Only the path: the width, height and mimeType live in the gallery
    hero: { path: "/public/val/images/hero_a1b2c.png" },
  },
);
A remote gallery
content/remoteGallery.val.ts
export default c.define(
  "/content/remoteGallery.val.ts",
  s.images({ directory: "/public/val/remote-images" }).remote(),
  {},
);