Form Elements
A field builder chooses the stored value type. .formElement() separately
chooses how a renderer should collect that value:
const budget = bd
.number()
.formElement('currency')
.validate({ positive: true, round: 2 })
Changing currency to another compatible numeric element changes input intent,
not the database type.
short_textbd.text()
.formElement('short_text')
.required()Element families
Text and choice elements
short_text, long_text, email, url, rich_text_input, dropdown,
radio_group, checkbox_group, choice_cards, services_selector,
phone_number, date, credit_card, collection_select, timePicker,
time_picker.date, time_picker.time, color
Object and compound elements
address_group, name_group, measurement, availability, object, geo,
date_range, time_picker_timeslot, time_picker_datetime
Array elements
multi-select, checkbox_group_many, choice_cards_many,
services_selector_many, tags, formFileValue
Boolean and numeric elements
yes_no_toggle, yes_no_checkbox, phone_number_basic, currency, range,
star_rating, happiness_rating
Compatibility
createSchema() compares the selected element with the stored field type.
An incompatible choice produces a warning and the compiled field includes
recommendedFormElements.
Examples:
| Stored type | Compatible intent examples |
|---|---|
TEXT | short_text, long_text, dropdown, radio_group, choice_cards |
NUMBER, NUMERIC | currency, range, star_rating, happiness_rating |
BOOLEAN | yes_no_toggle, yes_no_checkbox |
SELECT | dropdown, radio_group |
MULTI_SELECT | multi-select, checkbox_group, tags |
RELATION | collection_select |
FILES | formFileValue |
Element metadata
The optional second argument carries element-specific metadata:
const score = bd
.number()
.formElement('range', {
min: 0,
max: 100,
step: 5,
unit: 'percentage',
})
The ElementMetadata union supports:
- choice-card definitions,
- range bounds and units,
- measurement configuration,
- object property schemas,
- file limits and MIME types,
- address restrictions.
Structured builders such as bd.measurement(), bd.object(), bd.file(),
bd.address(), and bd.geo() select their natural form element and metadata
automatically.
Name element
name_group collects a person's name in explicit parts. Declare it on a JSON
field:
const contactName = bd.json().formElement('name_group')
The submitted value is one object:
{
"prefix": "Dr.",
"first": "Jane",
"middle": "Quinn",
"last": "Doe",
"suffix": "Jr.",
"nicknames": ["Janie"],
"full": "Dr. Jane Quinn Doe Jr.",
"short": "Jane Doe"
}
first and last always render; the optional parts (prefix, middle,
suffix, and nicknames) are switched on per field in the form builder.
full (every provided part joined) and short (first + last) are computed
server-side at submission validation — whatever a client sends for them is
recomputed. Nicknames may be submitted as a comma-separated string; the server
normalizes it into a trimmed array.
Dynamic choices
const assignee = bd
.text()
.formElement('dropdown')
.dynamicOptions({
endpoint: '/api/team-members',
method: 'GET',
headers: { 'x-source': 'project-form' },
cachePolicy: 'stale-while-revalidate',
})
The SDK stores this configuration. The renderer is responsible for fetching and presenting the options.
Form-element metadata is a definition, not component state. Open menus, selected values, focus, touched state, and current errors belong to the renderer's live store.
Next: Enums.