Problem
A select field rendered inside an <instatic-loop> prints the option's id, and there is no token that gives the label — so a select can be stored and edited, but not displayed.
A data table Trainings with a language select:
content_get_collection_schema →
{ id: "language", label: "language", type: "select", options: [
{ value: "p6MvZXfduFA8btVpRkUDt", label: "cz" },
{ value: "9QeLmLrHgyWUoOKMxqOpG", label: "en" } ] }
The Data workspace grid shows cz in the cell. The published page, from
{currentEntry.language} inside the loop, shows:
<span class="sye-term__metaitem">…<svg/>p6MvZXfduFA8btVpRkUDt</span>
Same field, same row, two different values depending on which surface you read it from. On a course listing that cell is meant to read "CS" / "EN"; it reads a 21-character opaque id next to the language icon.
There is no way to reach the label. site_list_loop_sources advertises exactly one token per field — currentEntryToken(fieldId) in server/ai/tools/site/readTools.ts returns {currentEntry.${fieldId}} with no per-type variants — so no .label is offered, and nothing in the loop docs (docs/features/loops.md) mentions that select fields differ from every other type.
The label is not missing from the model. server/plugins/host/handlers/contentProjection.ts already projects select and multiSelect as options: [{ value, label }] for plugin consumers, so the pairing exists and is surfaced elsewhere — just not to the renderer.
Every other field type resolves to something displayable. Select is the only one whose token output cannot be put in front of a visitor.
Proposed solution
Expose the label. Either is fine, and the second is the smaller change:
- Add a member token.
{currentEntry.<field>.label} for the option label and {currentEntry.<field>.value} for the id, leaving the bare {currentEntry.<field>} as-is so nothing breaks. entryField.ts already documents this shape for media — "object members are exposed directly while the original object remains at value" — so select would follow a pattern the codebase has.
- Make the bare token render the label, and keep the id available at
{currentEntry.<field>.value}. Better default (the common case is display), but a behaviour change for anyone keying CSS or data- attributes off the id today.
Whichever way, site_list_loop_sources should list the extra token for select/multiSelect fields so a client can discover it, and docs/features/loops.md should say what a select resolves to.
For multiSelect the same question applies to joining several labels — a comma-joined string for the bare token would match what the grid shows.
Alternatives considered
- Store the language in a Text field instead. Works, and is the workaround in place. It gives up validation and the option list, and duplicates data that the select already models correctly. It also means re-creating the field, because an existing field's type cannot be changed even while the table is empty.
- Map the id to a label in a runtime script. Possible — the site already patches the shared layout from JS — but it hard-codes generated ids into a script, and they are exactly the thing that changes when someone edits the option list.
- Hide the cell. What the page does today. Fine while all rows share one language; useless as soon as an English course is listed.
Area
AI
Observed through the MCP connector against a live hosted workspace on 4 Sep 2026: field schema read with content_get_collection_schema, tokens listed with site_list_loop_sources, output checked in the published HTML.
Problem
A
selectfield rendered inside an<instatic-loop>prints the option's id, and there is no token that gives the label — so a select can be stored and edited, but not displayed.A data table
Trainingswith alanguageselect:The Data workspace grid shows
czin the cell. The published page, from{currentEntry.language}inside the loop, shows:Same field, same row, two different values depending on which surface you read it from. On a course listing that cell is meant to read "CS" / "EN"; it reads a 21-character opaque id next to the language icon.
There is no way to reach the label.
site_list_loop_sourcesadvertises exactly one token per field —currentEntryToken(fieldId)inserver/ai/tools/site/readTools.tsreturns{currentEntry.${fieldId}}with no per-type variants — so no.labelis offered, and nothing in the loop docs (docs/features/loops.md) mentions that select fields differ from every other type.The label is not missing from the model.
server/plugins/host/handlers/contentProjection.tsalready projects select and multiSelect asoptions: [{ value, label }]for plugin consumers, so the pairing exists and is surfaced elsewhere — just not to the renderer.Every other field type resolves to something displayable. Select is the only one whose token output cannot be put in front of a visitor.
Proposed solution
Expose the label. Either is fine, and the second is the smaller change:
{currentEntry.<field>.label}for the option label and{currentEntry.<field>.value}for the id, leaving the bare{currentEntry.<field>}as-is so nothing breaks.entryField.tsalready documents this shape for media — "object members are exposed directly while the original object remains atvalue" — so select would follow a pattern the codebase has.{currentEntry.<field>.value}. Better default (the common case is display), but a behaviour change for anyone keying CSS ordata-attributes off the id today.Whichever way,
site_list_loop_sourcesshould list the extra token for select/multiSelect fields so a client can discover it, anddocs/features/loops.mdshould say what a select resolves to.For multiSelect the same question applies to joining several labels — a comma-joined string for the bare token would match what the grid shows.
Alternatives considered
Area
AI
Observed through the MCP connector against a live hosted workspace on 4 Sep 2026: field schema read with
content_get_collection_schema, tokens listed withsite_list_loop_sources, output checked in the published HTML.