SfSkills Domains Docs GitHub

Home / flow / flow-dynamic-choices

flow-dynamic-choices

Build Flow choice sets from records, picklist fields, or collections, including dependent choices. Triggers: dynamic choices Flow, record choice set, dependent picklist Flow, FlowDynamicChoiceSet, picklistField, collectionReference, valueField, displayField, outputAssignments, choiceReferences, defaultSelectedChoiceReference, semicolon multi-select output. NOT for static hard-coded choices — use flow/screen-flow-choice-component-selection.

Open the skill folder on GitHub


Flow Dynamic Choices

Screen Flows often need choices that reflect current data — active Accounts, open Cases, active picklist values. Record Choice Sets pull from SOQL; Picklist Choice Sets pull from field metadata; Collection Choice Sets iterate a variable. This skill covers each plus dependent-picklist patterns and empty-state handling. Sourcing the choices and rendering them are largely separate decisions — a Record, Picklist, or Collection Choice Set can drive a plain Picklist or Radio Buttons set, while the Visual Picker renders only standalone Choice resources that carry an icon (it doesn't support Record or Picklist Choice Sets). For long or filterable lists, a Choice Lookup component renders any Choice resource as a searchable, typeahead selector with single- or multi-select.

This skill owns the resource internals: which of the three sources to use, the FlowDynamicChoiceSet field shape, filter/sort/limit and their cost per screen render, defaults and re-entry, the multi-select semicolon output, dependent choices, and how to verify any of it without a FlowTest. Which component renders the choices belongs to flow/screen-flow-choice-component-selection; the screen's own design belongs to flow/screen-flows.


Before Starting


Questions to Ask Before Configuring

AskWhy it mattersWhat a good answer adds
"Where do these choices come from — a picklist field's value set, a query, or a collection this flow already holds?"It decides the type, and the type decides everything else. Setting picklistField + picklistObject makes it a picklist choice and disables displayField, filters, object, outputAssignments, sortField, sortOrder and valueField, each "Not supported for picklist choices" (api_meta.txt L70269–L70386)The <dynamicChoiceSets> block itself, not a description of the data — including the dataType that the type forces (Gotcha 6)
"How many rows will this return on the biggest account/track/region, and in what order should they appear?"limit is "Maximum and default: 200" (L70319–L70321), so omitting it caps at 200 rather than removing a cap; and "if sortField and sortOrder are also specified, the records are sorted before the limit takes effect" (L70321–L70322)An explicit <limit>, a sortField that carries the Sort API field property, and a sortOrder — so the truncation is deterministic instead of arbitrary (Gotcha 4)
"What should the user see, and what should the flow store?"displayField is the label, valueField is the stored value, and they are usually different — "the displayField could be the account 'Name' while the valueField is the account 'Id'" (L70383–L70389)Two field API names instead of one, and a check that the label is actually unique enough for a human to choose between two rows
"Which fields of the selected record does anything after this screen need?"outputAssignments (assignToReference + field, both required, L70813–L70823) is the only way a record choice set hands you a second field. Without it, authors add a Get Records to re-fetch the row the choice set already hadA named list of fields and target variables, which removes a whole query from the design (Gotcha 7)
"What happens when this filter matches nothing?"FlowDynamicChoiceSet extends FlowElement, not FlowNode (L70267–L70268, L70393–L70398) — no connector, no faultConnector. An isRequired field over an empty set is an interview the user cannot leaveA Get Records before the screen with a Decision on its result — which then also feeds the choice set via collectionReference, so the query is paid for once (Gotcha 2)
"Do the filter criteria ever need OR, or a mix of AND and OR?"FlowRecordLookup declares filterLogic (L71124–L71131); FlowDynamicChoiceSet's twelve documented fields do not (L70278–L70389). Multi-condition logic cannot live on the choice setA decision to move the logic to a Get Records feeding a collection choice set, before the XML is written rather than after the deploy fails (Gotcha 5)
"Can the user go back and change the answer this choice set depends on?"allowBack defaults to true (L71434–L71452) and the choice set re-queries on re-render, while inputsOnNextNavToAssocScrn defaults to UseStoredValues — the previously stored selection survives even if it is no longer in the set (L71733–L71745)Either ResetValues on the dependent field, or allowBack false with an explicit restart path — decided deliberately rather than inherited from the default (Gotcha 3)

What a proper configuration adds over just doing it: a choice set whose type, dataType and field set follow from where the data actually lives; a truncation point and an order you chose rather than inherited; every downstream field arriving from the row already fetched; and a verification plan that survives the fact that FlowTest cannot run against a screen flow.


Choice Source Selection

The sourceTypeRequired shapeQuery at render?Floor
A picklist or multi-select picklist field's value setPicklist choice setpicklistField + picklistObject, dataType Picklist or MultipicklistNo — field metadataAPI 35.0
Records matching criteria, chosen fresh each renderRecord choice setobject + displayField + valueField, dataType not Picklist/MultipicklistYesAPI 25.0 for limit/sortField/sortOrder
A collection this flow already holds (Get Records, Loop output, a text collection)Collection choice setcollectionReferenceNo — reads memoryAPI 54.0
A fixed list the author typesStatic FlowChoice in <choices>choiceText + dataType + valueNo—
A fixed list where one option needs free textStatic FlowChoice + userInputisRequired, promptText, validationRule; not on multi-select fieldsNo—

Choosing between the last two and the components that render them: flow/screen-flow-choice-component-selection.


FlowDynamicChoiceSet Field Map

The twelve fields the guide enumerates (api_meta.txt L70278–L70389), and which kind of choice set each belongs to:

FieldRecordPicklistCollectionNotes
dataTyperequired, not Picklist/Multipicklistrequired, must be Picklist or MultipicklistrequiredRecord value is API 54.0+
objectrequirednot supported—The object queried
displayFieldrequirednot supported—What the user reads
valueField—not supported—What the flow stores; picklist choices always store the API value
filterssupportednot supported—FlowRecordFilter[]; value can be an elementReference
limitsupportednot supported—Maximum and default: 200; API 25.0+, nillable 45.0+
sortField / sortOrdersupportednot supported—Applied before limit; sortField needs the Sort API field property
outputAssignmentssupportednot supported—assignToReference + field, both required
picklistField / picklistObjectnot supportedrequired—API 35.0+; these two are the discriminator
collectionReference——requiredAPI 54.0+
filterLogicdoes not exist on this type——It exists on FlowRecordLookup (L71124–L71131)

Consuming the Choice Set on a Screen

choiceReferences is a string[] naming FlowChoices or FlowDynamicChoiceSets, and it is supported on exactly four fieldType values — RadioButtons, DropdownBox, MultiSelectCheckboxes, MultiSelectPicklist (api_meta.txt L71588–L71601). Three rules that trip people up:


Key Considerations


  1. Pick the source with the Choice Source Selection table, then write the dataType the type

    forces. Getting this wrong is a deploy failure, not a run-time bug.

  2. Answer the seven Questions above and write the answers into

    templates/flow-dynamic-choices-template.md. The limit, the sortField, the outputAssignments list and the empty-set branch all come from that sheet, not from the XML editor.

  3. Write the XML from references/metadata-examples.md §1, adapting the object names. It is a

    complete two-screen flow with a picklist choice set, static choices with a userInput, a dependent record choice set with filters/sortField/limit/outputAssignments, a collection choice set, a multi-select field, and a Decision on the chosen values. §2 has the Multipicklist variant; §3 has the semicolon-to-collection routes.

  4. Put the empty-set branch in before the screen, not on it. A Get Records with the same filters,

    a Decision on its result, and — if the same rows feed the screen — a collection choice set over its output, which also gives you the faultConnector a choice set cannot have.

  5. Run the checker —

    python3 skills/flow/flow-dynamic-choices/scripts/check_flow_dynamic_choices.py --manifest-dir <source tree> --strict — and clear every ERROR. E1/E2 catch the dataType discriminator, E4/E5 the screen-field enum, E8 the default that isn't in the list, E9 a multi-select wired to a non-text variable.

  6. Deploy in the order in references/metadata-examples.md §5 (objects and value sets → FLS →

    flow as Draft), then work the §6 debug-run checklist: least-privileged persona, a Workflow log at FINER for FLOW_ELEMENT_LIMIT_USAGE, a Back-then-Forward pass, a mid-interview data change, and the empty-set path. Do not write a FlowTest — it does not cover screen flows.

  7. Record every UNVERIFIED you resolved against your own org in the flow's <description>, so

    the next author inherits the answer instead of the question.


Worked Examples (see references/examples.md)


Common Gotchas (see references/gotchas.md)

  1. Sharing comes from runInMode, not from the choice set — and SystemModeWithSharing skips FLS.
  2. An empty result set plus isRequired is an interview the user cannot leave, with no fault path.
  3. allowBack re-renders the choice set but UseStoredValues keeps the stale selection.
  4. limit's default is its maximum; omitting it caps at 200 rather than removing a cap.
  5. FlowDynamicChoiceSet has no filterLogic — every filter combines implicitly.
  6. picklistField is the discriminator, and it forces the dataType both ways.
  7. outputAssignments is the only route to a second field from the selected record.
  8. FlowScreenField.dataType has no Picklist value; copying the choice set's fails the deploy.
  9. A multi-select field is one semicolon-joined string, and it strips semicolons from your values.
  10. There is no split — no operator and no formula turns a delimited string into a collection.
  11. A DropdownBox with no default silently selects choiceReferences index 0.
  12. defaultSelectedChoiceReference names a FlowChoice, and only one, even on multi-select.
  13. Screen flows cannot be FlowTested — the debug log is the instrument.
  14. A Visual Picker choice with no icon renders as a plain list.
  15. Choice Lookup's display cap hides distant options.
  16. Multi-select Choice Lookup needs a collection output and Lightning runtime.

Top LLM Anti-Patterns (full list in references/llm-anti-patterns.md)


Proactive Triggers

Surface these WITHOUT being asked:


Output Artifacts

ArtifactDescription
Source decisionPicklist vs record vs collection vs static, with the dataType the type forces and the API floor it needs
Deployable flow XML*.flow-meta.xml with the choice sets, the dependent filters, the screens and the fault routing, shaped from references/metadata-examples.md §1
Query budgetlimit, sortField, sortOrder per choice set, plus whether any of them can collapse into one Get Records + collectionReference
Output mapEvery outputAssignments field → variable pair the downstream logic needs
Empty-set planThe Get Records, the Decision and the message screen that stop a required field over an empty set
Debug-run checklistThe §6 verification steps, since FlowTest does not cover screen flows
Checker reportERROR/WARN/ADVISORY findings from scripts/check_flow_dynamic_choices.py

Official Sources Used


Reference Files

FileRead it when
references/metadata-examples.mdYou are writing or reviewing actual *.flow-meta.xml: a complete two-screen flow with all four choice sources, the Multipicklist variant, the semicolon-to-collection routes, package.xml, deploy order, and the debug-run verification checklist
references/gotchas.mdThe flow deploys and then does the wrong thing quietly — sharing, the empty set, allowBack re-render, the 200 default, the missing filterLogic, index-0 defaults, and the FlowTest negative
references/llm-anti-patterns.mdYou are reviewing generated Flow XML or Flow choice advice, or self-checking your own — including the invented SPLIT(), the copied Picklist dataType, and the generated FlowTest
references/examples.mdYou want the narrative walk-through, the dependent-filter fragment, or the table of what a multi-select field actually stores, before writing XML
references/well-architected.mdYou need the pillar tradeoffs, the query-budget levers, or the source and guide line behind any claim in this skill
templates/flow-dynamic-choices-template.mdYou are recording the source decision, the query budget and the output map for someone else to build or review
scripts/check_flow_dynamic_choices.pyBefore every deploy and against any fixture directory. --manifest-dir <source tree>, optional --strict; exits 1 on any ERROR

Package files