Skip to main content

Field Collection Component

Purpose​

The field-collection component edits an array field inside a form. It renders one template per array item and supports add, soft or hard remove, remove-all, drag-and-drop reorder, item defaults, list/grid/accordion item layouts, and grouped collections.

Use it for repeated sub-records such as line items, contacts, business hours, accessorial rows, or task lists.

Compact hierarchical rows​

Accordion collections now render compact, hierarchical rows. Optional itemIcon, itemSubtitle, itemBadges, and itemNestedCount props add an icon tile, muted metadata, semantic badges, and a collapsed nested-record count. Badges support danger, warning, info, success, primary, and neutral theme colors plus a template-driven when guard.

Setting label enables a collection header with an item-count chip, a summaryTemplate subline, and Expand all / Collapse all controls. The add action moves into this header unless addButton.position is explicitly set. Nested collections render a compact section header and default to collapsed accordion rows; use collapseNested: false or an explicit layout to keep the previous expanded behavior.

When itemTitle is omitted, autoItemTitle defaults to true and derives a useful title from the first label-like scalar field (name, title, label, or description) plus up to two metadata values. Newly added blank records open automatically. density accepts compact (default) or comfortable.

Source updates​

Frontend updates added group-level grid controls and keyboard-friendly reorder controls for grouped collections:

  • groupCols controls how many groups render per row.
  • groupSpacing controls Material UI grid spacing between group columns.
  • showMoveButtons renders up/down controls when options.allowReorder is true.
  • options.removeType controls whether individual row removal soft-deletes the row with isDeleted: true or physically removes it from the array.
  • Reorderable object rows get a stable internal _uuid only when drag handles or move buttons are shown, so reordering follows the row instead of repainting by array index. Non-reorder collections keep their payloads untouched.

Group props only affect groupMode: true; item layout inside each group still uses layout, cols, and spacing.

Props​

  • fieldName (string, required): Form array field binding.
  • itemTemplate (component or component array, required): Template rendered for each item.
  • itemHeaderFields (component or component array): Interactive fields rendered in an accordion summary, even while the row is collapsed. They use the same item, index, collection, and field-name prefixing as itemTemplate.
  • itemType (object | string | number | boolean | auto): Type of item to create and edit. Defaults to object.
  • options.allowAdd (boolean): Show add button. Defaults to true.
  • options.allowRemove (boolean): Show remove buttons. Defaults to true.
  • options.allowRemoveAll (boolean): Show remove-all button. Defaults to false.
  • options.allowReorder (boolean): Enable drag-and-drop reorder. Defaults to true.
  • options.minItems / options.maxItems (number): Minimum and maximum item counts.
  • options.removeType (soft | hard): Individual remove behavior. Defaults to soft, which marks object rows with isDeleted: true; use hard to splice the item out of the array.
  • addButton.label, addButton.icon, addButton.variant, addButton.position: Add button customization.
  • removeButton.label, removeButton.icon, removeButton.variant: Remove button customization.
  • defaultItem (any): Default values for newly added items.
  • onItemAdd (action list): Runs after adding an item with item, index, fieldName, and parentItem variables.
  • onItemRemove (action list): Runs after soft or hard removal with the removed item, its index, fieldName, and parentItem.
  • dotsMenu.items (array): Replaces the built-in Delete-only menu. Each item supports label, disabled, permission, onClick, and remove; use remove: true to invoke the configured collection removal behavior.
  • layout (list | grid | accordion): Item layout mode. Defaults to list.
  • cols (number): Item grid columns when layout: grid.
  • spacing (number): Spacing between items.
  • groupMode (boolean): Enable grouping.
  • groupBy (string): Item field used as the group key.
  • groups (array): Group definitions with key, label, and optional icon.
  • groupTemplate (component): Optional custom group header template.
  • itemGroups (object): In accordion layout, visually join consecutive rows whose templated key resolves to the same non-empty value. Supports optional headerTemplate and templated accent frame color.
  • groupCols (number or breakpoint object): Number of group columns. Example: 2 or { xs: 1, md: 2, lg: 4 }. Defaults to 1.
  • groupSpacing (number): Spacing between group columns. Defaults to 0.
  • showIndex (boolean): Show item index numbers.
  • showDragHandle (boolean): Show drag handles.
  • showMoveButtons (boolean): Show up/down move buttons for accessible reordering. Requires options.allowReorder: true.
  • showDivider (boolean): Show dividers between list items.
  • containerClass / itemClass (string): CSS class hooks.
  • itemTitle (string): Field name or template for accordion item title.
  • defaultExpanded (boolean): Expand accordion items by default.
  • label (localized string): Section label above the collection.
  • itemIcon / itemSubtitle (string templates): Optional accordion icon and metadata.
  • itemBadges (array): Inline semantic badges with label, optional color, and optional when.
  • itemNestedCount (string template): Collapsed-row nested-record count.
  • nestedCountLabel (localized string): Nested-count wording.
  • summaryTemplate (string template): Header summary; receives count and items.
  • showCount / showExpandAll (boolean): Header count and bulk expansion controls; both default to true.
  • collapseNested (boolean): Collapse nested collections by default. Defaults to true.
  • autoItemTitle (boolean): Derive titles from record fields. Defaults to true.
  • density (compact | comfortable): Accordion row padding preset.
  • rowVariant (card | flat): Row chrome. flat replaces each bordered row card with dividers while retaining the open-row accent. Defaults to card.
  • nestedVariant (panel | rail | none): Nested collection chrome. rail uses a left border and indent; none removes wrapper chrome. Defaults to panel.

Always-visible header fields​

Use itemHeaderFields when an accordion row needs editable values in its summary. Wrap fields in a layout so grid sizing works inside the fixed-width header area. Interacting with these fields does not toggle the row.

itemHeaderFields:
component: layout
props: { cols: 0 }
children:
- component: Contacts/Select
name: assignedDriverContactId
props:
label: { en-US: Driver }
displayMode: readEdit
size: { xs: 6 }
- component: field
name: customValues.plannedDate
props:
type: datetime
label: { en-US: Planned Date }
displayMode: readEdit
size: { xs: 6 }

For nested collections, rowVariant: flat with nestedVariant: rail avoids stacked card borders. Use nestedVariant: none where the parent row already provides enough visual grouping.

On web viewports below the Material UI md breakpoint, accordion summary content can wrap instead of overlapping. The itemHeaderFields block takes a full-width line below the title and uses the available width; at md and above it keeps the fixed 480-pixel desktop area. Author the inner responsive field sizes normallyβ€”the enclosing layout continues to control their grid.

Grouped multi-column example​

component: field-collection
name: businessHours
props:
fieldName: businessHours
groupMode: true
groupBy: dayOfWeek
groupCols:
xs: 1
md: 2
lg: 4
groupSpacing: 2
groups:
- key: 1
label: { en-US: Monday }
- key: 2
label: { en-US: Tuesday }
- key: 3
label: { en-US: Wednesday }
- key: 4
label: { en-US: Thursday }
- key: 5
label: { en-US: Friday }
- key: 6
label: { en-US: Saturday }
- key: 0
label: { en-US: Sunday }
options:
allowAdd: true
allowRemove: true
allowReorder: true
removeType: soft
defaultItem:
startTime: "09:00:00"
endTime: "17:00:00"
layout: accordion
itemTemplate:
component: layout
props:
cols: 2
spacing: 2
children:
- component: field
name: startTime
props:
type: time
label: { en-US: Start }
- component: field
name: endTime
props:
type: time
label: { en-US: End }

Consecutive item groups​

itemGroups differs from groupMode: it preserves row order and joins only adjacent rows with the same resolved key. Runs of one, empty keys, and non-adjacent matching keys stay ungrouped. This is available in accordion layout.

itemGroups:
key: '{{ item.customValues.linkKey }}'
accent: warning
headerTemplate:
component: text
props:
value: '{{ group.size }} linked rows'

The header and accent templates receive group = { key, items, size, startIndex, endIndex } and collection. Each grouped row template also receives group, groupPosition (first, middle, or last), and zero-based groupOffset. Reordering a row can split a group because grouping is recalculated from visible order.

Behavior notes​

  • When individual removal is available, each item shows a theme-colored three-dots menu with a Delete action. This applies to list/grid rows and accordion headers; the configured removeType, minItems, and permission behavior are unchanged.
  • onItemAdd and onItemRemove let collections persist changes immediately. Both receive the enclosing parentItem for nested collections, the affected item, its index, and fieldName; action form helpers can write mutation results (such as a generated ID) back into the row.
  • A custom dotsMenu can combine removal (remove: true) with row actions. Custom actions receive the same item context; showing a custom menu does not require options.allowRemove.
  • In grouped mode, the component renders each configured group and filters items by groupBy.
  • Adding an item from a group automatically assigns that group's key to the groupBy field.
  • Individual remove soft-deletes rows by default (removeType: soft), preserving persisted child records for backend reconciliation. Set removeType: hard for transient arrays where removed rows should be dropped immediately.
  • Remove-all clears the full array regardless of removeType.
  • groupCols maps to a 12-column Material UI grid (groupCols: 3 renders each group at xs: 4).
  • showMoveButtons is useful on touch devices or dense forms where drag-and-drop is hard to operate.
  • Stable _uuid keys are ignored when detecting primitive wrapper items and are only backfilled for reorder UI collections.
  • Responsive groupCols values are converted per breakpoint, e.g. { md: 2 } becomes md: 6 grid width.