← Back to Component Index

Item Template JSON — Admin Reference

Every valid itemType, contentType, and renderType value across all sites, what each one fetches or displays, and the parameters each accepts
Audience: CMS admin team assembling pages from Stack/Carousel/Grid/ButtonGroup containers  |  Companion docs: Dynamic Feed — Template Resolution, Content Adapters & DynamicPageOrchestrator (engineering detail)  |  Dynamic Feed — API Contract & Rendering Pipeline (container/page shape)  |  Work Item: AB#1821  |  Updated: 2026-10-20 16:34 ET  |  Audited: 2026-09-16 16:14 ET

Three separate settings, easy to conflate: the container dropped onto a page (containerType: Stack, Carousel, Grid, or ButtonGroup) picks the layout shell. Each item inside that container has its own itemType, set directly on the item (not inside the Template JSON) — this is what kind of slot the item is (a button, a hero card, a contact row, or a template-driven List — see §2). Only when an item is meant to fetch real data does it also carry a Template JSON string, whose contentType says what to fetch and renderType says how each fetched row should look. This doc covers all three, organized item-first since that's the order an admin actually picks them in.

1. Static items vs. templated items

Every item starts with an itemType set directly on the item — this is not part of the Template JSON. Most itemType values (Button, ButtonCard, HeroCard, CardText, …) are simple, static visual slots: title/image/link are typed in directly and there's no Template at all (template: null).

An item becomes templated when it also carries a Template JSON string — either to fetch a single piece of live data (the signed-in pilot's own profile, their LEC link) onto an otherwise-static-looking slot, or to expand into a whole list of rows the admin doesn't know in advance (documents matching a category, a committee's roster, podcast episodes). For that second case, the convention used throughout every real site's content is to set the item's own itemType explicitly to List — a placeholder marking "this slot will be filled in dynamically" — and let the Template JSON's contentType and other parameters do the actual work of building it:

{ "itemType": "List", // ← ON THE ITEM ITSELF, not inside Template. Marks this slot as dynamic. "template": { "contentType": "...", // WHAT to fetch (drives the list's content) "renderType": "...", // HOW each fetched row displays "...": "..." // filter/scope parameters specific to that contentType } }

itemType, contentType, and renderType are all free-text strings, not fixed picklists enforced by the app. There is no validation today that rejects a typo or an incompatible pairing — an unrecognized contentType silently drops the item (the rest of the page still renders fine); an unrecognized renderType throws internally but is caught and the item is skipped. Nothing tells you it was skipped. The dropdown-driven admin UI should therefore only ever offer the exact values listed in §2–§4 below — never free text — since a mistyped value fails silently rather than with an error message.

2. itemType — what kind of slot the item is

Set directly on the item, sibling to (not inside) the Template. Values seen in real, live site content:

itemTypeWhat it isRequired fields (if static)
ListPlaceholder for a template-driven list — see §1. The item's own display fields are ignored; the Template's contentType/renderType decide everything about the resolved rows.—
ButtonPlain text button. The most common item type in every site.ctaText, ctaLink. Optionally carries a Template of just {"contentType":"ButtonCard","variant":"alpa"} or "alpa-diagonal" to render the branded stripe style instead of plain.
ButtonCardSquare/rectangular tile with an icon — used in Grid containers for quick-link menus.headerText, ctaLink; optional image (icon URL).
CardSmallSmall compact card (icon/image + short title) — also the renderType most single-row content resolves to (e.g. LecLink, Committee).title, image, ctaLink (or driven entirely by Template).
HeroCardLarge, prominent card with image + description — used standalone (static) or as the renderType for fetched content like documents/podcasts.title, image, link. (Legacy fields blurb/icon still work as fallbacks for description/image but should not be used in new content.)
PilotCardThe personalized pilot greeting card. Always paired with a Template (contentType: "PilotCard") since it needs the signed-in pilot's session.Template required — see §3.
ContactCardA single static contact row (name/role/phone/email).rosterTitleToken/rosterNameToken/etc. typography tokens; otherwise driven by Template when fetched via ContactItem.
MultiCommitteeRosterRenders the combined roster for several committees at once: for each committee, in the order listed, a heading with the committee's name, then its members, officers first.A Template with contentType: "RosterItem" and a rosterCodes parameter — a comma-separated list of committee codes, e.g. "UALLEC00097,UALLEC00107" (see §3 and §6). A top-level rosterCodes field on the item is not read.
CardTextText-only card, no image.label (eyebrow), title, description, link.
PromoBannerFull-width promotional banner.title, description, image, link.
ToggleSwitchAn on/off toggle row.title.
SearchSecondaryButtonSecondary search-entry button.ctaText, ctaLink.
ExpanderCollapsible/expandable section.title, description (body when expanded).
TabGroupA set of tabs.title (tab label).
EmergencyButtonHigh-visibility emergency-contact button (red background).ctaText, ctaLink (usually a tel: link).
SingleButton2Alternate single-button style.ctaText, ctaLink.
ThreeUpButtonRow of exactly three icon+label buttons.threeUpButtons array of {icon, label, link}, exactly 3 entries.
SliderImagesA carousel-within-an-item image slider.sliderTitle, sliderItems array of {imageUrl, eyebrow, title, blurb, link}.

ButtonGroup containers only keep Button items — any other itemType placed inside a ButtonGroup container is silently filtered out client-side.

3. contentType — what to fetch

contentTypeWhat it fetchesProducesStatus
PilotCardNo data fetch — builds a personalized greeting card for the signed-in pilot (name, rank, contract link) from the device's own login session.1 rowLive
LecLinkA single link row to the signed-in pilot's own LEC (Local Executive Council) page, based on their MEC/LEC/base airport.1 rowLive
DocumentItemDocuments from the document library, filtered by category or grouping.N rows (itemType: "List")Live — the highest-volume contentType in real content
CommitteeThe MEC's list of committees.N rowsLive
MecHotelDirectoryThe signed-in member's MEC crew-hotel directory — airports and their hotels, as the backend returns them for that member's MEC (security-trimmed per MEC).One flat, ordered list: a search field, then for each airport a header followed by that airport's hotel rowsNew — live on one UAL page, ual-committees-hotel-list ("Hotel Directory"), reached from a "HOTEL LIST TEST" button on ual-committees-hotel
ContactItemThe volunteer roster (officers/members) for one specific committee.N rows (itemType: "List")Live — heavily used, second-highest volume
RosterItemThe volunteer rosters of several committees at once, one headed section per committee, in the order the codes are listed. Every live multi-committee roster attaches it to an item whose itemType is MultiCommitteeRoster.For each committee: a heading with its name, then its member rowsLive — 20 roster items in the fallback content (UAL 12, DAL 8)
PodcastEpisodeEpisodes from an RSS podcast feed.N rows (itemType: "List")Live
ButtonCardNo data fetch — this is a styling selector, not a fetch. Attached to a plain Button item to render it as the branded stripe button (see variant, §5) instead of a plain text button.0 rows — decorates the existing item in placeLive
HeroCardNo data fetch — same styling-only pattern as ButtonCard, attached to an item whose itemType is already HeroCard. Used for a static hero card whose title/image/action are typed straight into the Template's parameters rather than the item's own fields, e.g. an "Access {mec} documents" tile with action: "/mec".0 rows — decorates the existing item in placeLive
(omitted)Leaving contentType off (Template null) entirely is valid — the item is fully static, using whatever title/description/image/link were typed directly on it.1 row (the item itself)Live

RosterItem is what makes an item a multi-committee roster. The committee list lives in the Template's rosterCodes parameter, and the item resolves like any other templated item, so hidden, visibleMecs, hiddenMecs and hiddenUserTypes apply to it and isFavoritable is honored. The app picks the roster by this content type, not by the item's itemType. An item-level rosterCodes field (with no Template) is not read: such an item shows nobody.

4. renderType — how to display it

Each contentType adapter has a sensible default renderType it falls back to if left blank, but it can be overridden. Observed valid values, by how the card looks:

renderTypeVisual resultTypically paired with
PilotCardThe personalized pilot greeting card (has its own dedicated layout; variant: "alpa" selects the ALPA-branded sub-style).PilotCard (always)
CardSmallSmall, compact card — icon/image plus a short title. The most heavily used renderType overall.LecLink, Committee
HeroCardLarge, prominent card with a bigger image and description — used for featured/lead content. Second most common renderType.DocumentItem (usual default), PodcastEpisode, hand-authored static hero items
ContactCardA person/contact row (name, role, phone, email) — the renderType used for essentially every ContactItem resolution.ContactItem (always, in practice)
CardTextText-only card, no image.hand-authored text cards
ButtonCardA simple tappable button-style card, no fetched data required. Also used as a value of contentType (see §3) when attached to a plain Button item — those two uses are independent.hand-authored, or a Button item's contentType: "ButtonCard" styling template

The following renderType values were not observed in any live mock content, but exist as their own itemType (§2) and can be reasonably expected to work as a renderType the same way: PromoBanner, Expander, TabGroup, ToggleSwitch, SearchSecondaryButton. Confirm with engineering before relying on one of these from a Template rather than a plain static item.

If unsure, leave renderType blank and let the contentType's adapter pick its default (LecLink → CardSmall, PilotCard → PilotCard, Committee → CardSmall, MecHotelDirectory → MecHotelRow). DocumentItem, ContactItem, and PodcastEpisode require renderType to be set explicitly — the item is silently dropped if it's left blank on those three.

5. Fields that work on any templated item

These sit alongside contentType/renderType in the same JSON object and apply regardless of content type:

FieldValid valuesEffect
hiddentrue / falseHides the item entirely when true.
visibleMecsComma-separated MEC codes, e.g. "UAL,DAL"; group tokens "USA"/"CAN" supported.Allow-list — item shows only for members of the listed MEC(s).
hiddenMecsComma-separated MEC codes.Deny-list — item hidden for members of the listed MEC(s).
hiddenUserTypesArray of strings, e.g. ["staff","guest"].Hides the item from the listed user types.
isFavoritabletrue / falseShows/hides the favorite (star) toggle on the card.
variantContent-type specific: "alpa" (branded), "alpa-diagonal" (branded diagonal-stripe — only confirmed on ButtonCard-styled Button items).Selects a visual sub-style within a renderType. Plain passthrough, no {token} substitution.
clampTitletrue / false (default true)A HeroCard placed directly on the page (its own title, image and link) only; a hero that a List builds from documents or podcast episodes ignores it. false shows the card's whole title instead of cutting it off after two lines; leaving it out, or true, keeps the two-line limit. Write false or "false"; on/off only, not a line count. Used for Home's "From the President" card. A hero with no Template gets this whole template: {"renderType":"HeroCard","contentType":"HeroCard","clampTitle":false}. Keep renderType and contentType: a template with no contentType, or with nothing else the app reads (a misspelled key such as ClampTitle, or a value such as 0 or "no"), removes the card from the page. With renderType present, a mistake only leaves the title cut at two lines. Plain passthrough, no {token} substitution.
title, eyebrow, description, image, ctaLink, linkPlain strings; support {token} placeholders (e.g. {mec}, {lec}, {airport}) filled in per-viewer.Overrides the card's own text/image/link when the content type doesn't otherwise fill it in, or for hand-authored (no contentType) cards.
actionLeft null in almost every real item. When set, seen as: a plain in-app route ("/mec", "/home-mec" — on a static HeroCard-styled item, §3), or a route template with an {Id} placeholder ("/mec/committee/{Id}" — Committee's per-row web-fallback link, §6). Supports {token} substitution the same as ctaLink/link.Sets the item's nav target (mirrors ctaLink/link — see §6's per-contentType notes for which name a given contentType expects).
containerTitlePlain string; supports {token}, e.g. "{mec} MEC".Sets the heading on the container this item lives in (not the item itself).
viewAllLinkNot populated on any item's Template in real content — see the note below.Sets the container's "View All" link (only takes effect when the container's own viewAllLink field, below, is empty).

When the four fields above (hidden, visibleMecs, hiddenMecs, hiddenUserTypes) hide every item in a container from a member, the whole container disappears for that member: no heading, no "View All" link, and for a carousel no "Off the Radar!" card. Home's "My MEC" carousel works this way for a GGN pilot and for Staff and Guest accounts. A hidden item is always hidden, but it never takes the rest of its container with it: a container with any item the fields did not hide always shows. That includes a document list that found nothing (a carousel shows its "Off the Radar!" card, a grid or stack its heading with nothing under it) and one that failed to load (it shows as loading and retries).

In practice, set viewAllLink on the container itself, not inside an item's Template. The Template-level viewAllLink key is real and does get lifted onto the container when present, but no item in any real site's content actually uses it — every site instead sets the container's own top-level viewAllLink field directly. Real values observed there, by shape:

ShapeExample
In-app page-key shorthand"{ual-media}", "{ual-lec-005-updates}", "{ala-communications}", "{aca-publications}"
Compound shorthand with a nested {mec}/{lec} token"{{mec}-events}", "{{mec}-lec-{lec}-updates}", "{{mec}-publications}"
Full in-app route"/dynamic-feed-orchestrator?page={alpa-updates}", "/mec"
Absolute external URL (usually a CMS search/results page)"https://ual.alpa.org/RESOURCES/Updates-Reports-Documents#cf-item-category=Committees,SOAR", "https://dal.alpa.org/Search#sortCriteria=%40itemdate%20descending&cf-item-category=Communications"

One malformed value was found in real content: site.DAL.json has a viewAllLink of "{dal-publications-contract2026" — missing its closing brace. Don't copy that pattern; always close a page-key shorthand with }.

6. Parameters by contentType

DocumentItem

FieldValid valuesNotes
filterType"Category" (by far the most common) or "Grouping" (seen once in live UAL content: ual-updates-committeeupdates uses filterType: "Grouping" with filterValue: "MEC Committee Updates" and the grouping field left null — the group name goes in filterValue)Required — picks which document filter to apply.
filterValueCategory or grouping name, e.g. "MEC Updates and Weekly", "Hotel Updates", "FAQ", "Pilot Compensation"Required. Free text — must match an actual document category name exactly.
filterValuesA JSON array of category (or grouping) names, e.g. ["Communications", "Hotel Updates"]Optional — one carousel or list from several categories (or several groupings, matching filterType). Their documents are merged: a document in two of them shows once, and docType and searchFilter apply to the merged set, so limit=3 is the 3 newest across all of them, not 3 from each. Without a date sort, categories show in the order listed. Each name must match a category exactly; one with no documents is skipped. Keep filterValue as well, set to one of the names: an app version from before this field reads only filterValue, so it shows that one category instead of an empty carousel. Must be an array — a single string such as "Communications, Hotel Updates" is ignored and only filterValue is used. One filterType per item: categories and groupings can't be mixed. For View All, give the page the container's viewAllLink opens the same filterValues (and filterValue) with a larger limit, so it lists the same combined set at length.
categorynull in every real item, with no exceptions — no site has ever populated this field.Optional — intended to further narrow a Grouping query. Leave omitted/null; there is no known-good example value to copy.
parentFilterType / parentFilterValue"MEC" or "LEC" / the code, e.g. "ual", "UAL", or a numeric LEC code like "005", "063"Scopes to one airline/local group. Case of the value itself is inconsistent across existing content (both "UAL" and "ual" seen) — match whatever the source system uses.
scopenull in every real item, with no exceptions — no site has ever populated this field.Present in the parameter bag but has no known-good example value; leave omitted/null.
groupingnull in every real item — never populated for DocumentItem specifically (compare ContactItem's grouping below, which does see real use).Present in the parameter bag alongside filterType: "Grouping"; still never populated, even in the one live Grouping item (see filterType above).
searchFilter"sort_by=date&order=desc&limit=3"Use exactly this query-string form. The colon-delimited form ("by:date-direction:desc-top:3") was the pattern in older site files, but the app's parser only understands the query-string form, so any remaining colon-delimited values are silently no-ops. The current UAL site file (2026-09) uses the query-string form on every item that sets searchFilter (e.g. limit=5, limit=10, limit=25). New/edited content should use the query-string form.
actionnull in every real DocumentItem — always left out since the document viewer route is set automatically per row.Optional per-row tap override; no known-good non-null example exists for this contentType specifically (compare Committee's action below).

Committee

FieldValid valuesNotes
actionRoute template with {Id}, e.g. "/mec/committee/{Id}"Per-row web-fallback tap destination.
searchFilter"sort_by=name&order=asc"Defaults to alphabetical by name if omitted/unrecognized.
featuredCommitteesJSON object mapping a committee code to an icon URL, e.g. {"UALHOTL00001":"https://.../hotel-icon.svg"}Featured committees are pinned in the given order ahead of the rest.
featuredCommitteePagesJSON object mapping the same committee code to an in-app CMS page key, e.g. {"UALHOTL00001":"ual-committees-hotel"}Overrides the destination page for a featured committee when tapped in-app (action above is the web fallback).

In real content, a Committee template is typically attached directly to a CardSmall item (not an itemType: "List" placeholder) — either convention works, since the app never reads the placeholder item's own itemType once a factory resolves it.

ContactItem

FieldValid valuesNotes
filterType"RosterCode" (most content), "LecReps" (AB#2863) or "MecReps" (AB#2840)Required. "RosterCode" resolves one committee's own volunteer roster; "LecReps" resolves the signed-in pilot's own LEC reps instead (getlecreps) — a fallback source for LECs with no AMPS committee group to point at; "MecReps" resolves the signed-in pilot's MEC officers (getmecreps). Read Officer and rep sections below before using "MecReps".
filterValueCommittee/roster code, e.g. "UALHOTL00001", "ACAMEC00007"Required for filterType: "RosterCode". Ignored for filterType: "LecReps" and "MecReps" — omit it or leave any value, it has no effect in those modes.
parentFilterType / parentFilterValueSame as DocumentItemOptional scoping. Not read in LecReps or MecReps mode.
grouping"Officers" is the only non-null value ever seen, anywhere, across every site. Otherwise null.Accepted but not currently applied — the full roster returns regardless of this value, so "Officers" doesn't actually filter anything today even where it's set. Not read at all in LecReps or MecReps mode.
scope, category, searchFilter, actionnull in every real item — no exceptions found.Present in the parameter bag; leave omitted/null, there is no known-good example value.

filterType: "LecReps" and "MecReps" rows show the favorite heart when the rep record carries the person's id (memberId, the same id a committee volunteer carries), and favorite as that person, so an officer, the same person's rep record and their committee rows are one favorite and, in Search, one card. A rep record without that id has no heart.

Row order is automatic. Every ContactItem roster (both filterTypes), every RosterItem roster, the LEC roster page and Search list officers first, by one shared title list in the app (a volunteer's title, a representative's office or office code): any Chair title (any subject chair, such as Safety Chair, included) and the National President and Vice President offices, then Vice Chair, then Secretary or Secretary-Treasurer, then Treasurer, then Executive Administrator, then Captain Representative, then First Officer Representative (a plural such as Captain Representatives ranks the same), then everyone else. Titles match whatever their capitals, and a space, a hyphen or any other dash (an en or em dash pasted from a document), a slash or a backslash (including their full-width, division and fraction forms), or an invisible character pasted with the text (a zero-width space, a soft hyphen, a byte-order mark) between or around words is the same, so Vice-Chair ranks as Vice Chair and Secretary/Treasurer as Secretary-Treasurer. Beyond that list, a title whose last word is Chair (or Chairman, Chairwoman or Chairperson) ranks as Chair, or as Vice Chair with Vice before that word, a note in brackets at the end such as (Interim) ignored; a Past, Former or Emeritus chair and Chair-Elect are not ranked. The same reading decides when two titles from one committee are the same line on a person's card. Within the same rank, a person's sortorder (from the roster data, not the Template) comes first, then legal last name, then legal first name, for committee members, reps and MEC officers alike (a nickname never moves a person). There is no Template field for ordering; a title that should rank but doesn't needs adding to that list in the app.

One card per person, on the roster, in Search and in Favorites (AB#2840). The people a ContactItem or RosterItem section lists are what members find in the app's Search and see in Favorites, so how a section is set up shows there too:

Officer and rep sections (MecReps, LecReps)

What they list (AB#2840). A ContactItem section with filterType: "MecReps" lists the signed-in pilot's MEC officers, straight from the officer data (getmecreps); filterType: "LecReps" lists their own council's LEC reps (getlecreps). Both need renderType: "ContactCard", like every ContactItem, and honor isFavoritable and the visibility fields.

Moving an officer or rep section onto MecReps / LecReps. Today these people are mostly authored as committee rosters (e.g. UAL's "MEC Officers", UALMADM00003, and the council "REPRESENTATIVES" sections), which rank as committee lines. To move one:

  1. Wait for the app. Don't re-author until the first app release that knows MecReps is widely installed: an older build doesn't know the filter and shows the section empty.
  2. Replace, don't add. Change the existing roster section's filterType (and drop its filterValue) rather than adding a second section beside it. Two sections listing the same people show them twice on the page.
  3. Keep its place and settings. Leave the section where it is, with its visibility, isFavoritable and roster typography tokens: the rows keep the section's look, and its place on the page decides where its people sit in Search.
  4. Check the page and Search with a member of that MEC: every officer once, in office order, and a search for an officer's name finds one card with their officer line first.

RosterItem

FieldValid valuesNotes
rosterCodesComma-separated committee codes, e.g. "UALLEC00097,UALLEC00107"Required. Sections appear in the order listed, not in the order the server returns committees. A repeated code (any letter case) shows once, at its first position; an unknown code, or a committee with no published members, is skipped. A committee whose name is blank in the data is headed by its code.
renderType"ContactCard"Optional; defaults to ContactCard, which is what every live roster uses (none sets it). Applies to the member rows; the headings are always headings.
isFavoritabletrue / falseOptional, default true. Same meaning as on ContactItem: false hides the favorite hearts on every member row.
hidden, visibleMecs, hiddenMecs, hiddenUserTypesSee §5Hide the whole roster from the members they name, like any templated item.
Typography tokensrosterTitleToken, rosterNameToken, rosterEmailToken, rosterTelToken, set on the item, not in the TemplateStyle each member's role, name, email and phone. Every member row inherits them from the item.

If the committee data can't be loaded, or none of the codes has published members, the roster shows nothing; the rest of the page is unaffected.

PodcastEpisode

FieldValid valuesNotes
filterType"FeedUrl" (only value seen)Required.
filterValueRSS feed URL, e.g. "https://feed.podbean.com/.../feed.xml"Required.
searchFiltere.g. limit/top segmentFeed is already newest-first; only a result-count limit has effect. Same query-string-vs-colon-form caveat as DocumentItem applies.

LecLink

FieldValid valuesNotes
parentFilterType"MEC"Always this value in real content.
parentFilterValueMEC code, e.g. "UAL", "ALA"Required.
filterType"LEC" (only value seen)—
filterValue"SELF" (only value seen)Always resolves to the signed-in pilot's own LEC.
imageURL/filename pattern with a {lec} token, e.g. ".../{lec}-card-sm.jpg"Optional — overrides the default image, substituting the pilot's resolved LEC code.

MecHotelDirectory new

A one-line Template — it has no filter or scope parameters. Which airports and hotels appear is decided by the backend for the signed-in member's MEC, so there is nothing to configure per site beyond placing it.

FieldValid valuesNotes
contentType"MecHotelDirectory"Required — the only field the directory needs.
renderType"MecHotelRow" (what the live UAL page sets) or blank (defaults to MecHotelRow)No other value is meaningful for this content type today; overriding it would send hotel rows to a card layout that does not know their fields.
filterType, filterValue, parentFilterType, parentFilterValue, searchFilter—Not read. Do not set them expecting to narrow the list.
hidden, visibleMecs, hiddenMecs, hiddenUserTypesAs in §5Optional, and apply to the item like any other. They control whether the directory section shows; the hotel data itself is already trimmed to the member's MEC by the backend.

What it produces, and how it behaves. The Template resolves into one flat, ordered list — a search field, then for each airport (alphabetical by airport code; airports with no hotels are skipped) a header ("CODE · Airport Name") followed by that airport's hotel rows. Grouping is the item order, so the list must be rendered as-is.

PilotCard

FieldValid valuesNotes
filterType"MEC" (always)—
filterValue"SELF" (always)—
ctaLinkDeep-link string, e.g. "/document-open?queryTagID=AppContractLink"Route opened when the pilot taps "View Contract".
variante.g. "alpa"Optional visual sub-style.
isFavoritabletrue / falseUsually false for this card.

ButtonCard styling only

Attached to a plain Button item, not a fetch-producing content type. Accepts variant ("alpa" or "alpa-diagonal"), plus the common visibility fields from §5 (hiddenUserTypes, hiddenMecs, visibleMecs) and filterType/filterValue/ctaLink when it also needs a per-pilot deep link.

MultiCommitteeRoster Template: RosterItem

Put it in a Stack container. In a Stack each committee's heading sits directly above that committee's members, as one list. In a Carousel or Grid the roster still resolves, but each heading and each member becomes its own slide or tile, so the sections no longer read as sections.

Set itemType: "MultiCommitteeRoster" and attach a Template with "contentType": "RosterItem" and the rosterCodes to show, in display order (parameters in the RosterItem table above). The item's own display fields are ignored; the four roster*Token typography tokens on the item apply to every member row. An item-level rosterCodes field is not read: an item that has only that field shows nobody.

7. How this relates to the Stack/Carousel/Grid/ButtonGroup dropdown

When assembling a page, two independent choices happen at two different levels:

LevelSettingValid valuesControls
Container (the thing dropped onto the page)containerTypeStack, Carousel, Grid, ButtonGroupThe overall layout shell the items sit inside. Grid also takes an optional columns integer (defaults to 3 when omitted).
Item (each slot inside the container)itemTypeSee §2What kind of slot the item is.
Item's Template (only for fetched content)contentType / renderTypeSee §3 / §4What data fills that slot and which card style it renders as.

In practice: an admin first picks the container (say, Carousel), then for each item inside it picks an itemType (say, List for fetched content), then a contentType (say, DocumentItem) and, if needed, overrides the renderType (say, HeroCard) plus that content type's filter parameters from §6. The container choice does not constrain which itemType/contentType/renderType values are valid — any content type can be placed in any container shape (with the one exception noted in §2: ButtonGroup keeps only Button items) — so the admin dropdown can treat the container and item choices independently.

8. Example payloads, drawn from real site content

Each example below shows the item's itemType alongside its Template JSON, exactly as they appear together on the item.

Pilot greeting (single row)

"itemType": "PilotCard", "template": { "renderType": "PilotCard", "contentType": "PilotCard", "filterType": "MEC", "filterValue": "SELF", "ctaLink": "/document-open?queryTagID=AppContractLink", "isFavoritable": "false" }

LEC link (single row)

"itemType": "CardSmall", "template": { "renderType": "CardSmall", "contentType": "LecLink", "parentFilterType": "MEC", "parentFilterValue": "ALA", "filterType": "LEC", "filterValue": "SELF", "image": "https://ala.alpa.org/Portals/90/alpa-app/card-sm/{lec}-card-sm.jpg" }

Document list (list, HeroCard rows)

"itemType": "List", "template": { "renderType": "HeroCard", "contentType": "DocumentItem", "parentFilterType": "MEC", "parentFilterValue": "ual", "filterType": "Category", "filterValue": "MEC Updates and Weekly", "searchFilter": "sort_by=date&order=desc&limit=3" }

Committee list (attached to a single CardSmall item)

"itemType": "CardSmall", "template": { "renderType": "CardSmall", "contentType": "Committee", "action": "/mec/committee/{Id}", "featuredCommittees": { "UALHOTL00001": "https://.../hotel-icon.svg" }, "featuredCommitteePages": { "UALHOTL00001": "ual-committees-hotel" } }

Committee roster (list, ContactCard rows)

"itemType": "List", "template": { "renderType": "ContactCard", "contentType": "ContactItem", "filterType": "RosterCode", "filterValue": "UALHOTL00001", "grouping": "Officers" }

MEC hotel directory (list, placed in a Stack container)

"itemType": "List", "template": { "renderType": "MecHotelRow", "contentType": "MecHotelDirectory" }

This is the exact shape of the live UAL ual-committees-hotel-list page: one Stack container (columns: 1) holding a single List item with this Template. The item on that page also carries roster*Token values (the same tokens the committee-roster items use); the directory's rows are built by the factory and do not read them, so they have no effect.

Podcast episodes (list, HeroCard rows)

"itemType": "List", "template": { "renderType": "HeroCard", "contentType": "PodcastEpisode", "filterType": "FeedUrl", "filterValue": "https://feed.podbean.com/example/feed.xml" }

Branded button (styling only, no fetch)

"itemType": "Button", "ctaText": "IRROPS RECOVERY GUIDE", "ctaLink": "https://example.org/irrops.pdf", "template": { "contentType": "ButtonCard", "variant": "alpa-diagonal" }

Multi-committee roster (in a Stack container)

"itemType": "MultiCommitteeRoster", "rosterTitleToken": "RosterTitle", "rosterNameToken": "RosterName", "rosterEmailToken": "RosterEmail", "rosterTelToken": "RosterTel", "template": { "contentType": "RosterItem", "rosterCodes": "UALLEC00097,UALLEC00107,UALLEC00212" }