select Field Type
type: 'select' maps a raw field value to a human-readable label via the options array. The raw value is matched with strict equality (===) against each option's value property. If no match is found, the raw value is displayed as a string.
Core Examples
Basic Select Rendering
Status mapped from string values; Priority mapped from numeric values.
{
key: 'status',
label: 'Status',
type: 'select',
options: [
{ value: 'active', label: 'Active' },
{ value: 'inactive', label: 'Inactive' },
{ value: 'pending', label: 'Pending' },
],
},
{
key: 'priority',
label: 'Priority',
type: 'select',
options: [
{ value: 1, label: 'Low' },
{ value: 2, label: 'Medium' },
{ value: 3, label: 'High' },
],
},
Fallback for Unmatched Values
When no option matches the raw value, the raw value is rendered as a plain string. This makes gaps in your options list immediately visible.
'silver' is not in the options list — Mateo's tier renders as the raw string 'silver'.
{
key: 'tier',
label: 'Tier (partial options)',
type: 'select',
options: [
{ value: 'gold', label: 'Gold' },
// 'silver' intentionally omitted — falls back to raw string
],
},
Formatter
formatter runs before the options lookup. Use it to normalise raw values (e.g. trim whitespace, lowercase) so they reliably match your options.
formatter lowercases and trims the status value before the options lookup fires.
{
key: 'status',
label: 'Status (normalised)',
type: 'select',
options: [
{ value: 'active', label: 'Active' },
{ value: 'inactive', label: 'Inactive' },
{ value: 'pending', label: 'Pending' },
],
formatter: (value) => String(value ?? '').toLowerCase().trim(),
},
Condition
condition receives the full entity and returns true to show the field or false to hide it. Evaluated per row.
Tier column only renders for active users. Mateo (inactive) gets no Tier cell.
{
key: 'tier',
label: 'Tier (active only)',
type: 'select',
options: [
{ value: 'gold', label: 'Gold' },
{ value: 'silver', label: 'Silver' },
],
condition: (entity) => entity.status === 'active',
},
Field Options Reference
| Option | Type | Default | Effect |
|---|---|---|---|
key | string | required | Entity property to read the value from. |
label | string | unset | Column header or card label. |
type | 'select' | — | Maps raw value to a label via options. Falls back to String(value) on no match. |
options | { value, label }[] | unset | The lookup table. value can be string, number, or boolean; matched with ===. |
formatter | (value, entity) => unknown | unset | Runs before the options lookup — use to normalise raw values before matching. |
condition | (entity) => boolean | unset | Hides the field for rows where the function returns false. |
align | 'left', 'center', 'right' | 'left' | Text alignment in table mode. |
width | CSS length or number | unset | Column width in table mode. |
showLabel | true, false | true when label is set | Shows or hides the label in card/grid layouts. |
renderAs | string | unset | Replace select rendering. Use badge for colour-coded labels. |
Caveats
- The match is strict (
===). A numeric value1will not match a string option{ value: '1' }. - There is no built-in colour or styling on
type: 'select'. UserenderAs: 'badge'with acolorMapfor visual category indicators. formatteroutput is what gets matched againstoptions.value— not the original raw value.
Why select vs text + formatter?
type: 'select' and type: 'text' with a formatter produce identical rendered output today. The distinction is semantic: select declares that a field has a finite, enumerable set of valid values, and the options array is the canonical definition of that set.
Future versions of Widgemo — or add-on packages — may use options to drive:
- Filter dropdowns that enumerate the known values for a column
- Inline editing inputs (a
<select>element pre-populated with your options) - GroupBy controls that label groups using the option labels rather than raw values
Using type: 'select' now means your field config will be forward-compatible with those capabilities without changes. If the field is truly open-ended text, use type: 'text'. If it has a fixed set of values, use type: 'select'.
Performance
:::tip Stable options reference
widgemo-core builds an internal Map from your options array for O(1) lookups. This Map is only rebuilt when the options reference changes. Define your options array outside your render function — or memoize it with useMemo if constructed dynamically — so the Map is reused across renders.
// Good — stable reference, Map built once
const statusOptions = [
{ value: 'active', label: 'Active' },
{ value: 'inactive', label: 'Inactive' },
];
// Avoid — new array every render, Map rebuilt every render
// options={statuses.map(s => ({ value: s.id, label: s.name }))}
:::
See Also
- reference Field Type
- badge Renderer
- Item Config — item-level shape and layout contract
- Field Config