Dropdown Data Source Options
Connecting Dropdown and Select components to live data rather than static option lists keeps your UI in sync with your data without manual maintenance. This page covers the advanced data source configuration that controls how options are fetched, labelled, searched, sorted, grouped, and paginated.
Overview
By default a Dropdown or Select field in a Form block accepts a static list of { label, value } objects. Switch to a data source mode and the options come from a live query — a REST endpoint, GraphQL response, or entity collection. UnifyApps maps the response fields to labels and values, applies optional filters, and supports incremental loading for large datasets.
Note: Open the field's inspector in the Form block's Fields editor. Select the Dropdown or Select field, then switch Options Source from Static to Data Source. The data source properties below become available.
Data Source Properties
| Property | Type | Default | Description |
dataSource | data source ID or binding expression | — | The data source that provides the options. Select an existing data source from the picker, or use a binding expression such as {{ countriesQuery.data.objects }} to provide the options array directly. |
labelField | string | — | The field name from each record to display as the option label — what the user sees. Example: name, displayName, title. |
valueField | string | — | The field name to use as the option's underlying value — what gets stored in form data on selection. Example: id, code, slug. |
searchField | string | Same as labelField | The field searched when the user types into a searchable dropdown. Defaults to labelField. Override with a different field (e.g. email) when users search by something other than the displayed label. |
filter | binding expression | — | A pre-filter applied to the options before they are displayed. The expression receives each record and should return a boolean — e.g. {{ item.active === true }}. When the expression is falsy for a record, that record is excluded from the options list. |
sort | object: { field, direction } | — | Sort the options before display. field is the record key to sort by; direction is asc or desc. Applied after the data source response is received, so this is a client-side sort over the loaded options. |
pagination | boolean | false | When true, options are loaded incrementally as the user scrolls to the bottom of the dropdown. The data source must support server-side pagination with page and pageSize parameters. Useful for large datasets (hundreds or thousands of options). |
groupBy | string | — | A field name by which to group the displayed options under headers. Options with the same value for this field are collected under a labelled group heading. Example: group a product list by category. |
Event Properties
| Property | Type | Description |
onOptionsLoad | event handler | Fires after the data source query completes and options are ready. The event payload contains options — the final array of { label, value } objects after filtering, sorting, and grouping. Use to set a default selection based on the loaded options. |
Example: Country Dropdown from REST Endpoint
Country selector — REST data source with sort
// Data source: fetchCountries (GET /api/reference/countries) // Response shape: { data: [ { code: "IN", name: "India", region: "Asia" }, ... ] } dataSource: fetchCountries labelField: name valueField: code sort: { field: "name", direction: "asc" } groupBy: region // Result: options grouped by region (Africa, Americas, Asia, Europe, Oceania) // Each option shows the country name; form stores the country code on selection.
Example: User Picker from Entity Collection
Assignee picker — entity collection with filter and search
// Entity collection: User // Fields: id, displayName, email, department, active dataSource: listUsers // entity data source, fetches all users labelField: displayName valueField: id searchField: email // users type an email address to search filter: {{ item.active === true && item.department === currentUser.department }} // Only active users in the same department as the logged-in user are shown. // Searching by email lets users find colleagues by address rather than name.
Example: Paginated Product Selector
Product picker — paginated, server-side search
// Data source: searchProducts (GET /api/products?q={{searchQuery}}&page={{page}}&pageSize=20) // The data source accepts a dynamic search query input. dataSource: searchProducts labelField: productName valueField: sku searchField: productName pagination: true // When the user types "bolt", the dropdown triggers searchProducts // with q="bolt" and loads the first 20 results. // Scrolling to the bottom loads the next page automatically.
Tip: When a dataset has more than a few hundred records, avoid loading all options upfront. Configure a data source that accepts a search parameter, set pagination: true, and wire the user's search input to the data source's query parameter. This keeps the initial load fast and the search responsive.
Dependent Dropdowns
A common pattern is a dependent or cascading dropdown — the options in one dropdown are filtered based on the selection in another. For example, choosing a country first, then showing only the cities in that country.
Cascading country → city dropdowns
// Country dropdown (standard data source, all countries) // City dropdown: dataSource: fetchCities // GET /api/cities?countryCode={{countryField.value}} labelField: cityName valueField: cityId // The data source input countryCode is bound to the form's country field value. // When the user changes the country selection, the data source re-runs and // the city dropdown updates with the new country's cities automatically.
Warning: When the parent dropdown changes (e.g. country is switched), the child dropdown's current value may no longer be valid. Add an onChange handler on the parent field that clears the child field's value — e.g. call setFieldValue('city', null). Otherwise the form may submit a city that belongs to a different country.
Troubleshooting
| Symptom | Likely cause | Fix |
| Dropdown shows no options | Data source has not run, or labelField / valueField do not match the response field names | Trigger the data source manually and inspect its Output panel. Verify field names are an exact case-sensitive match. |
| All options show as "undefined" | labelField points to a field that does not exist or is nested | Use dot notation for nested fields: labelField: "address.city", or flatten the response with a transform. |
| Search does not filter options | searchField is set to a non-string field, or the data source does not accept a search parameter | Ensure searchField points to a string field. For server-side search, wire the search input to a data source input parameter. |
| Groups show "undefined" as header | groupBy field is missing or null on some records | Records with a null groupBy value are placed in an "Other" group by default. Ensure all records have the grouping field populated, or filter them out with the filter property. |