Components
radio
A group of mutually exclusive radio buttons. Use when the user must pick exactly one option from a small, always-visible list.
A group of mutually exclusive radio buttons. Use when the user must pick exactly one option from a small, always-visible list.
Read Form Rules before using this component — keys, labels, required fields, expressions, visibility, and validation all follow shared conventions.
When to use
- 2–5 mutually exclusive options that benefit from being always visible
- The choice has significant downstream consequences (drives conditional visibility of other fields)
- Options are short labels that read well side-by-side or stacked
When NOT to use
Instead of radio, use… | For… |
|---|---|
customdropdown | More than ~5 options, or when space is constrained |
checkbox | Single opt-in/opt-out (yes/no boolean) |
multicheckbox | Multiple selections from a list |
Props
| Prop | Type | Required? | Description |
|---|---|---|---|
label | string | required | Visible label. Title Case for nouns, Sentence case for questions. Must be unique across the form. |
required | boolean | required | Always false. The expression controls the runtime value. |
defaultRequired | boolean | required | true for required fields, false for optional ones. |
options | array | required | Array of { label, value } objects. label is shown; value is stored in the model. |
placeholder | string | optional | Descriptive text shown above the options (often mirrors the label). |
tooltip | string | optional | Short help text shown as an icon tooltip next to the label. |
hint | string | optional | Subtle help text rendered below the field, always visible. |
hideField | boolean | optional | Hides the field and excludes its value from submission. Toggle via expressions["props.hideField"]. |
Examples
Required radio group driving conditional visibility
The selected value is used in expressions["hide"] on dependent fields.
{
"key": "FIELD_IS_THE_INMATE_ABOVE_18_OR_BELOW_18",
"type": "radio",
"props": {
"label": "Is the Inmate above 18 or below 18?",
"placeholder": "Is the Inmate above 18 or below 18?",
"required": false,
"defaultRequired": true,
"options": [
{ "label": "Above 18", "value": "Above 18" },
{ "label": "Below 18", "value": "Below 18" }
]
},
"expressions": {
"props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired",
"hide": "!(model?.FIELD_INMATE_CITIZENSHIP === 'Rwandan')"
},
"validation": {
"messages": {
"required": "This field is required."
}
}
}A field that appears only when a specific radio option is selected
{
"key": "FIELD_SOME_DEPENDENT_FIELD",
"type": "input",
"props": {
"label": "Some Dependent Field",
"required": false,
"defaultRequired": true
},
"expressions": {
"props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired",
"hide": "!(model?.FIELD_IS_THE_INMATE_ABOVE_18_OR_BELOW_18 === 'Above 18')"
},
"validation": {
"messages": {
"required": "This field is required."
}
}
}Checklist
-
keyisUPPER_SNAKE_CASEand unique across the entire form -
props.labelis present, unique, and correctly cased - Field is nested at the correct depth:
sections > formly-group > block > radio -
required: falseis set (nevertrue) -
defaultRequiredis set (trueorfalse) -
expressions["props.required"]is present with the exact required expression -
optionsis a non-empty array of{ label, value }objects -
validation.messages.requiredis present - If options exceed 5, consider
customdropdowninstead