← Back to Blog

Attachments belong in the form — and 5.1 hides them behind three defaults

An inspection form assembling text fields, a multiple-choice element and a photo attachment element into a single feature record written back to a hosted feature layer

Attachments have always been the awkward part of an ArcGIS editing app. The form was one thing — fields, domains, Arcade-driven visibility, a layout you configured — and attachments were a separate panel bolted on beside it, with no awareness of anything the inspector had just typed. Maps SDK for JavaScript 5.1, released June 2026, closes that gap: attachments become a first-class form element inside the same FormTemplate as everything else.

The feature is genuinely good. It also ships behind three defaults — two that render the element invisible and a third that silently disables its best property — plus a keyword rule that can hide every attachment already sitting on your layer. None of them fail loudly. This article is mostly about them.

Read this before you debug anything. Adding an AttachmentElement to a form template is not enough on its own. Default one: FormTemplate.supportsAttachmentElements is false — without setting it, the form ignores attachment elements no matter which editor you use. Default two: on the deprecated Editor widget, formSystem is legacy and renders none of the new elements. Default three: useOriginalFilename is true, which makes filenameExpression inert. None of the three throws or warns. You get a form that validates and is quietly missing what you configured.

What 5.1 actually added

Three things, and the middle one exists to serve the first.

First, AttachmentElement — a form element you place in FormTemplate.elements alongside your field and group elements. Second, a family of typed attachment inputs that constrain what an attachment may be: ImageInput, DocumentInput, AudioInput, VideoInput, SignatureInput, and the general AttachmentInput — which, as we will see, is the one that saves you on an existing layer. Third, MultipleChoiceInput, which finally gives forms a real checkbox-and-radio control instead of a coded-value domain pressed into service.

The 5.1 release notes frame it as attachment authoring being “integrated into the same configurable form experience, allowing attachment management to follow the overall form layout and behavior.” That is the point. An attachment element obeys the same visibilityExpression and editableExpression Arcade hooks as any other element, so the photo slot can appear only when the inspector marks a defect — something that previously meant hand-building the attachment UI yourself.

The element, property by property

The API surface is small and most of it earns its place:

PropertyWhat it doesWhy you care
input The typed input — image, document, audio, video, signature, or general. Constrains the picker. It is a UX constraint, not a content check — see the security note below.
minAttachmentCount / maxAttachmentCount Required minimum and permitted maximum. Validation you used to write by hand, and usually wrote inconsistently.
filenameExpression Arcade expression that generates the stored filename. The quiet winner — but inert unless you also change a default. See below.
useOriginalFilename / allowUserRename Keep the uploaded name; let the user edit it. Both default to true. These two decide whether filenameExpression ever runs.
displayFilename Shows or hides the filename in the form. Cosmetic, but worth turning on while you are testing a filename expression.
attachmentKeyword Tags the attachment with a keyword. Lets two elements write to distinct buckets — before photos and after photos. Also the property most likely to hide your existing data.
visibilityExpression / editableExpression Arcade-driven show and lock. Conditional capture without custom UI code.

The code

The element autocasts its input, so you rarely import the input classes directly:

import FormTemplate from "@arcgis/core/form/FormTemplate.js";
import AttachmentElement from "@arcgis/core/form/elements/AttachmentElement.js";
import FeatureLayer from "@arcgis/core/layers/FeatureLayer.js";

const photos = new AttachmentElement({
  label: "Defect photos",
  input: {                      // autocasts to ImageInput
    type: "image",
    maxImageSize: 1600          // PIXELS on the longest edge, not a file size
  },
  attachmentKeyword: "defect",
  displayFilename: true,
  minAttachmentCount: 1,
  maxAttachmentCount: 5,
  useOriginalFilename: false,   // REQUIRED, or filenameExpression never runs
  filenameExpression: "$feature.asset_id + '-' + Text(Now(), 'YMMDD')",   // Y, not YYYY
  visibilityExpression: "hasDefect"
});

const formTemplate = new FormTemplate({
  title: "Pole inspection",
  description: "Complete every section before submitting",
  supportsAttachmentElements: true,   // DEFAULTS TO FALSE. Without this, nothing renders.
  elements: [photos],
  expressionInfos: [{
    name: "hasDefect",
    expression: "$feature.condition != 'OK'",
    returnType: "boolean"
  }]
});

const poles = new FeatureLayer({
  portalItem: { id: "<your-item-id>" },
  outFields: ["*"],
  formTemplate
});

Four lines in there are load-bearing, and three of them are corrections to the obvious version.

Esri’s own sample will mislead you here. The AttachmentElement reference page shows maxFileSize: 800 inside a block commented “autocastable to ImageInput”. ImageInput has no maxFileSize property — it has inputMethod, maxImageSize and type. maxImageSize is a pixel dimension on the longest edge, and larger images are resized with aspect ratio maintained. The property called maxFileSize exists only on DocumentInput, and it is in megabytes. Copy the vendor sample onto an image input and your size cap is silently dropped — you have capped nothing, and every full-resolution phone photo goes straight into the storage bill. Verify against the input class you are actually using, not the element page.

expressionInfos is what visibilityExpression refers to by name — the expression lives on the template, not the element. filenameExpression is the exception to that pattern: per the docs it should be handled inline on the element rather than as a shared reference.

And watch the date token. Arcade’s Text() format specifiers define Y for the full year and YY for a two-digit year. There is no YYYY. Write it anyway and it parses as two two-digit years, so 2026 renders as 2626 — a wrong filename, generated silently, in the one property you added the expression for. Esri’s own default for this property uses Y.

Trap one: the template that ignores attachment elements

The first default is the one to check before you debug anything else, because it sits on the class you are already constructing. FormTemplate.supportsAttachmentElements indicates whether the form supports attachment elements at all, and it defaults to false. Leave it alone and any attachment element you configured is simply not part of the form.

This one is editor-agnostic. It bites the Editor component just as hard as the widget, which matters because the component is otherwise the configuration-free path — and it is easy to read “available by default in the Editor component” in the release notes as meaning there is nothing to set. There is exactly one thing to set, and it is on the template.

Trap two: the filename expression that never runs

filenameExpression is the property most worth having and the easiest to configure into uselessness. It applies only when useOriginalFilename is false, or when allowUserRename is false and the user adds an attachment without naming it. Both properties default to true.

So the natural configuration — set filenameExpression, leave everything else alone — keeps the original camera filename and never evaluates your expression. You get exactly the IMG_4471.jpg you were trying to eliminate, with no indication that anything was ignored.

Trap three: formSystem defaults to legacy

The new elements are rendered by a new form system. The Editor componentarcgis-editor — uses it by default. The Editor widget does not, and must be told:

// Editor WIDGET (deprecated at 5.0)
const editor = new Editor({ view, formSystem: "next" });   // constructor form; more robust
// editor.viewModel.formSystem = "next";                   // also valid, post-construction

The default is legacy, deliberately, to preserve behavior for applications built before 5.1. Defensible by Esri, and it produces a nasty failure to debug: a form template that validates, an element simply absent from the rendered form, and nothing in the console explaining why.

Do not flip this flag blind. The 5.1 release notes are explicit that applications relying on EditorViewModel.featureFormViewModel or EditorViewModel.attachmentsViewModel should remain in legacy mode until they have migrated to the Editor component. Those break when you set formSystem to next — not later, when you migrate. If you drive your own UI off either view model, the one-line opt-in is the thing that breaks production, not the migration.

Worth knowing that the bridge is itself temporary: formSystem, and support for the legacy form APIs, are documented for removal at 6.0 when next becomes the default.

And the keyword that hides your existing photos

This is the one most likely to bite a real project, and it is the reason the general AttachmentInput exists.

When you use a specific typed input — image, audio, video, document — existing attachments are displayed only if they match the element’s keyword. Attachments without a matching keyword are not shown. And when a form supports attachment elements but defines none explicitly, existing feature attachments are not displayed at all.

Picture the retrofit. A utility adds an AttachmentElement with attachmentKeyword: “defect” to a pole-inspection layer carrying forty thousand legacy photos. Not one of them has that keyword. Crews open records and see nothing. The data is intact and entirely invisible. To show attachments that have no corresponding keyword, use the general AttachmentInput and set its attachmentAssociationType accordingly. The docs also describe a compatibility fallback for forms authored under older workflows, where the Editor recognizes existing attachments and preserves prior behavior — find out which side of that fallback your layer lands on before you ship, not after.

Multiple choice, at last

MultipleChoiceInput is the smallest of the three additions and the one your field crews will notice first. Choices are an array of label and value pairs, with minimumChoices and maximumChoices for validation, choiceDelimiter controlling how several selections serialize into one field value, an includeSelectAllChoices convenience, and an otherChoice escape hatch. Note that otherChoice writes to a separate field you name via its fieldName property — it does not append free text into the delimited value.

That delimiter deserves a decision rather than a default. It defaults to a comma, selections are concatenated into a single field value, and a comma inside a label will produce a value you cannot parse back apart. Pick a delimiter your labels cannot contain, and pick it before anyone collects data.

What it costs

ATS rule: never assume a feature is free. Attachments are storage, and storage is credits. Per the ArcGIS Online credit documentation, the two rates that matter here are not the same:

WhatRateRoughly
Feature storage2.4 credits per 10 MB per month~240 credits per GB per month
File and attachment storage1.2 credits per 1 GB per month~1.2 credits per GB per month

Attachments bill at the file rate — 200 times cheaper per gigabyte than feature storage. Both are calculated hourly. A photo-heavy inspection program is therefore affordable on storage, which is the good news.

The form is not a spend ceiling. maxImageSize and maxAttachmentCount are client-side form configuration. Anything that calls the service’s addAttachment endpoint directly — another app, a script, a bulk loader — ignores them completely. Treat them as how you shape the intended workflow, not as a control on what the service will accept. If spend actually matters, govern it at the service and audit it, the same way you would treat minAttachmentCount as a hint rather than a guarantee.

Security and permissions, briefly

Two things the release notes will not tell you, and the first is easy to get backwards. Adding or deleting an attachment rides on the same Create or Update capability that governs feature editing — there is no separate per-user attachment permission to grant. The distinction is at the layer: the service must separately advertise attachment support, which is a different flag from whether the layer is editable. So the question to ask of a layer is not “who may attach files” but “does this layer advertise attachments at all” — and it must be editable too, or none of this works.

And the typed inputs are a picker constraint, not a content check. Declaring type: “image” shapes what the file dialog offers. It is not MIME sniffing, not malware scanning, and not server-side file-type enforcement. If you are capturing files from the public rather than from a known crew, that gap is yours to close.

The limitations that decide your design

The AttachmentElement reference lists nine constraints. Four shape the application:

Migrating off the widget, honestly

Widgets were deprecated at 5.0, and the docs say they will begin to be removed in Q1 2027 at version 6.0. Any editing app you expect to still be running a year from now is making this move regardless; 5.1 adds a reason to start sooner. But “migrate to the component” is a sentence, not a plan, so here is the honest shape of it.

Widget to web component is not a rename. The packaging differs, the event model differs — DOM events rather than watch and on handles — and the component expects a map component rather than a MapView handed to a constructor. Theming moves toward Calcite custom properties. Budget it as a real piece of work on any app with custom editing UI.

Two things make it less alarming than it sounds. EditorViewModel itself is not deprecated, so headless applications that drive their own interface are not being evicted. And the sequencing is under your control: if you depend on featureFormViewModel or attachmentsViewModel, stay in legacy mode and migrate deliberately rather than flipping a flag and finding out.

Where this lands in a real project

This is a meaningful upgrade for anything that captures evidence in the field — utility inspections, code enforcement, damage assessment, asset condition surveys. The pattern that used to require custom UI work — show the photo slot only when there is something to photograph, name the file after the asset, cap it at five, and lock it once the record is approved — is now four properties on a form element, three of them Arcade one-liners.

What it does not change is the data model. Attachments are still attachments, still billed as file storage, still bound to a layer that must have the capability enabled, and still governed at the service rather than at the form. What changed is that the form finally knows they exist — once you have found all three defaults.

References

Running an inspection program on a form nobody wants to fill in?

We design ArcGIS editing apps around the crew doing the work — conditional capture, enforced naming, validation that holds at the service and not just in the browser — and we build them on the component stack rather than the one being retired.

Book a free intro call