react-formbridge
Browse documentation
Componentsv1.0.2

FieldLabel component

Standalone label component returned by useFormBridge. Renders a field's label and required mark, reading both directly from the schema descriptor.

  • Label text comes from field.x('Label text') in the schema - the component stays in sync automatically, so you don't duplicate strings in JSX
  • Required mark is driven by .required() on the builder. Flip the schema and the asterisk appears/disappears everywhere
  • htmlFor defaults to the field name, which matches the id emitted by the generated fields - click the label, the input focuses, accessibility wired for free
  • Use it when you render inputs through form.fieldController(name) or when your design-system row layout keeps label / input / error as separate slots
  • Unlike Form and Form.Submit, FieldLabel keeps a deliberately focused API today instead of mirroring every native label attribute; if you need total control over the wrapper element, use render
FieldLabel.web.tsxtsx
1const schema = {
2 email: field.email('Email address').required(),
3}
4
5const form = useFormBridge(schema)
6
7<form.Form onSubmit={save}>
8 <div className="form-row">
9 <form.FieldLabel name="email" />
10 <input
11 id="email"
12 name="email"
13 value={form.state.values.email}
14 onChange={(e) => form.setFieldValue('email', e.target.value)}
15 onBlur={() => form.setFieldTouched('email', true)}
16 />
17 <form.FieldError name="email" />
18 </div>
19 <form.Form.Submit>Save</form.Form.Submit>
20</form.Form>

Why it exists

The generated <form.fields.email /> component already renders its own label inline. <FieldLabel /> exists for the cases where that isn't enough:

  • Custom layouts - you render the input yourself via form.fieldController('email') and want a drop-in label slot without re-implementing the required-mark logic
  • Design-system rows - your form grid keeps label / input / error in separate columns, and each slot is its own component
  • Single source of truth - the label text lives once in the schema; flipping a field between optional and required automatically updates every place <FieldLabel /> is mounted
  • Tooltips, icons, help popovers - use render to wrap the label in richer UI without giving up the typed name binding or the required-mark automation

Props

MethodTypeDescription
namekeyof SchemaRequired. Typed field name. Autocompletes from the schema keys so renaming a field surfaces a type error at the usage site.
childrenReactNodeOptional label override. When omitted, the component pulls label(...) straight from the schema descriptor - keep the text in one place instead of duplicating it in JSX.
render(ctx) => ReactNodeCustom render function. Receives { name, label, required, htmlFor } so you can build accessible labels with tooltips, icons, help popovers, etc.
renderRequiredMark() => ReactNodeReplaces the default red asterisk. Useful to swap for a localized (required) string or a design-system badge.
htmlForstring *(web only)*Explicit for attribute. Defaults to the field name, which already matches the input id emitted by the generated fields.
classNamestring *(web only)*Class applied to the default <label> element.
styleCSSProperties | StyleProp<TextStyle>Inline style - CSSProperties on web, StyleProp<TextStyle> on native.
render(...) for extra native attrs(ctx) => ReactNodeIf you need custom DOM/native attributes beyond the focused built-in surface, render the label element yourself via render and attach whatever your platform needs there.

Recipes

  • Schema-driven label → just <form.FieldLabel name="email" />. The text comes from field.email('Email address') in the schema
  • Ad-hoc override → pass children: <form.FieldLabel name="email">Work email</form.FieldLabel>
  • Localized required markrenderRequiredMark={() => <span>({t('required')})</span>}
  • Label with tooltip/help icon → use the render prop to wrap the label in your design-system tooltip
  • Shared row component → build a <FormRow name="email" /> wrapper that internally mounts FieldLabel, fieldController, and FieldError - the typed name flows through all three