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.

Stored fieldText
17 compatible elements
bd.text()TEXTShort text

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 typeCompatible intent examples
TEXTshort_text, long_text, dropdown, radio_group, choice_cards
NUMBER, NUMERICcurrency, range, star_rating, happiness_rating
BOOLEANyes_no_toggle, yes_no_checkbox
SELECTdropdown, radio_group
MULTI_SELECTmulti-select, checkbox_group, tags
RELATIONcollection_select
FILESformFileValue

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.