Search Large Choice Lists in XLSForm
To make a long list searchable in XLSForm, set the type to select_one_from_file facilities.csv and the appearance to minimal search. The options come from an attached CSV with name and label columns, and the enumerator types part of a label to narrow thousands of options to a few. Every example below compiles with pyxform and ODK Validate, the same check ODK Central runs when you upload a form.
How do I add a searchable list from a CSV file?
A facility survey needs the enumerator to pick one of 3,000 health facilities. Typing them onto the choices sheet makes the form slow to open and hard to update, so they go in facilities.csv:
name,label,district
10101,Kurigram District Hospital,1
10102,Ulipur Upazila Health Complex,1
20101,Rangpur Medical College Hospital,2
20102,Mithapukur Upazila Health Complex,2
The survey sheet then needs one row:
| type | name | label | appearance |
|---|---|---|---|
| select_one_from_file facilities.csv | facility | Which health facility are you visiting? | minimal search |
Three rules cover most mistakes:
- Keep the extension. The type is
select_one_from_file facilities.csv, with.csv. This is the opposite of pulldata(), which takes the file name without it. nameandlabelcolumns. The saved answer is thenamecolumn, sofacilitystores10101, not the hospital's name. Use numeric or short codes there.- Attach the file. The CSV is uploaded with the form, not pasted into it. It also works offline once the form is downloaded to the phone.
.xml and .geojson files work the same way. Excel files do not: save the sheet as CSV first.
What does the search appearance do?
search adds a text box above the options. The enumerator types any part of a label, upper or lower case, and only matching options stay visible. Typing ulip finds "Ulipur Upazila Health Complex".
minimal shows the list as a dropdown instead of a full screen of options. The two together, minimal search, are the usual choice for long lists, because the question then fits on a screen with other questions in a field-list group.
autocomplete is an older name for search. ODK's documentation now lists search as the recommended spelling, but forms that still use autocomplete keep working. Both also work on a list typed onto the choices sheet, so a 60-option list of districts can use minimal search without a CSV.
Search filters on the label only. If enumerators look facilities up by code, put the code in the label too, such as 10101 Kurigram District Hospital, or they will type the code and find nothing.
How do I filter a CSV list by an earlier answer?
Any extra column in the CSV can be used in choice_filter, just as on the choices sheet. Here the district column limits the search to the facilities of the district already picked:
| type | name | label | appearance | choice_filter |
|---|---|---|---|---|
| select_one district | visit_district | Which district is the facility in? | minimal | |
| select_one_from_file facilities.csv | district_facility | Which health facility are you visiting? | minimal search | district=${visit_district} |
| list_name | name | label |
|---|---|---|
| district | 1 | Kurigram |
| district | 2 | Rangpur |
The district codes on the choices sheet (1, 2) must match the district column of the CSV exactly. Filtering first also keeps the phone fast: searching 200 facilities in one district is quicker than searching 3,000. The cascading selects guide covers multi-level filters.
What if my CSV columns are not called name and label?
Use the parameters column to say which columns to read. This is handy when the list comes straight from a facility registry export:
| type | name | label | appearance | parameters |
|---|---|---|---|---|
| select_one_from_file facility_registry.csv | registry_facility | Which health facility are you visiting? | minimal search | value=facility_code label=facility_name |
value= names the column that is saved and label= the column that is shown. Only value, label, randomize and seed are accepted; any other word is an error.
For multi-select lists, select_multiple_from_file works the same way. The values in its name column must not contain spaces, because a select_multiple answer is a space-separated list:
| type | name | label | appearance |
|---|---|---|---|
| select_multiple_from_file crops.csv | crops_grown | Which crops did the household grow this season? | search |
To show the chosen label later in the form, for example in a confirmation note, see showing the label, not the value.
Should I still use the search() function?
Older forms load CSV options with a search('file') appearance and a placeholder row on the choices sheet. It still runs in ODK Collect, but it sits outside the ODK form specification, so newer features such as dynamic defaults do not work with it. Use select_one_from_file for new forms. For reference, this is the old pattern:
| type | name | label | appearance |
|---|---|---|---|
| select_one facility_list | legacy_facility | Which health facility are you visiting? | search('facilities') |
| list_name | name | label |
|---|---|---|
| facility_list | name | label |
The choices row is not an option: its name and label cells name the CSV columns to read. The function also takes a search mode, such as search('facilities', 'startswith', 'label', ${prefix}), with contains, startswith, endswith and matches. A filter written with choice_filter on select_one_from_file replaces most of these.
Common mistakes with searchable lists
These are the messages pyxform returns when ODK Central, KoboToolbox or the XLSForm converter rejects the form:
| You wrote | Write instead | Error you will see |
|---|---|---|
select_one_from_file facilities | select_one_from_file facilities.csv | File name for 'select_one_from_file facilities' should end with one of the supported file extensions: '.csv', '.xml', '.geojson' |
select_one_from_file facilities.xlsx | Save as CSV, then facilities.csv | Same "supported file extensions" error |
select_one_from_file facilities.json | Rename a GeoJSON file to .geojson | Same "supported file extensions" error |
choice_filter naming a question that does not exist | Use the exact name from the survey sheet | Reference variables must contain a name from the 'survey' sheet. Could not find the name 'district'. |
labels=facility_name in parameters | label=facility_name | Accepted parameters are 'label, randomize, seed, value'. The following are invalid parameter(s): 'labels'. |
| CSV not attached on the server | Upload it as a form attachment | No form error; the list is empty on the phone |
CSV filter column holds labels (Kurigram) | Use the parent's codes (1) | No error; the filtered list is empty |
The last two compile without complaint and only show up in testing, so open the form on a phone before training day. For other messages, see common XLSForm errors, or paste the form into the free XLSForm validator.
Does this work the same in ODK, KoboToolbox and SurveyCTO?
The select_one_from_file and search syntax is the same in ODK and KoboToolbox, because both read XLSForm. What differs is where the file goes and how each app handles very long lists:
| Platform | Where the CSV goes | Notes |
|---|---|---|
| ODK Central and Collect | Form attachments on the draft, before publishing | Works offline. Very long lists open faster when filtered with choice_filter first |
| KoboToolbox | Project Settings, then Media | Type to filter works in KoboCollect and Enketo for select_one; forum reports show it is unreliable for select_multiple in Enketo |
| SurveyCTO | Attached to the form as a .csv file or a server dataset | Loads CSV options with a search() expression in the appearance column and a choices row naming the value and label columns |
If one form must run on all three, keep the CSV columns plain (name, label, filter columns) and test it on each platform with the real file.
Why put long lists in a file?
A typed list catches problems a free-text answer never will. "Ulipur UHC", "Ulipur Upz" and "Ulipur health complex" are three spellings of one facility in a text field, and someone has to merge them in Stata later. A searchable list stores one code, 10102, every time, and updating the CSV next month does not mean editing the form.
You can describe the list in plain language instead: "let the enumerator pick a health facility from facilities.csv, filtered by the district chosen before, with a search box". LooprAI writes the rows, then compiles the form with pyxform before anything is saved.
Next: XLSForm cascading selects →
Frequently Asked Questions
How do I add a searchable dropdown in XLSForm?
Set the question type to select_one, or select_one_from_file for a CSV list, and write minimal search in the appearance column. The enumerator types part of a label and only matching options stay visible. The search is not case-sensitive and matches any part of the label.
What is the difference between search and autocomplete in XLSForm?
None in behaviour. autocomplete is an older alias for the search appearance, and both add a type-to-filter box above the options. ODK's documentation now recommends writing search. Forms that use autocomplete keep working in ODK Collect, KoboCollect and Enketo.
What columns does a select_one_from_file CSV need?
By default a name column, which is saved as the answer, and a label column, which is shown. To use other columns, write value=facility_code label=facility_name in the parameters column. Extra columns can be used in choice_filter expressions.
Why is my select_one_from_file list empty on the phone?
Usually the CSV was not uploaded as a form attachment, or a choice_filter compares against values the CSV does not have, such as labels instead of codes. The form compiles in both cases, so test on a phone with the real file before fieldwork.
How many options can a select_one_from_file list hold?
There is no fixed limit in ODK, but very long lists get slow to open and search on older phones and in web forms. Filter the list with choice_filter by an earlier answer, such as district, so each search runs over hundreds of rows rather than tens of thousands.
Does select_one_from_file work in KoboToolbox and SurveyCTO?
KoboToolbox reads it like ODK: upload the CSV under Project Settings, then Media. SurveyCTO loads CSV options with a search() expression in the appearance column and a choices row that names the value and label columns of the attached file.
No Credit Card Required
Build the form first. Add hosting when you need it.
Start free with LooprAI, then deploy a managed ODK Central server or run DataSnap checks when your project is ready.
Automation handles the mechanical work.
Researchers decide what the evidence means.