Skip to content
LuoForge/Tungsten
Components/FormField·

FormField

since v8.2.0

Validation-aware field wrapper. Composes the existing Label/HelpText/

ErrorMessage subcomponents and registers the control with the surrounding

FormProvider. Wires id / aria-describedby / aria-invalid /

aria-required onto the control purely through the (extended) FieldContext

— no cloneElement. See ADR-0004.

Install

Add the package and import the component.

pnpm add @hey-mike/tungsten
pnpm add @hey-mike/tungsten
import { FormField } from '@hey-mike/tungsten';
import { FormField } from '@hey-mike/tungsten';

Preview

Same fixtures used by the visual-regression suite.

Usage

apps/docs/app/snapshots/form-field/page.tsx

import { VariantGrid } from '../_components/VariantGrid';
import { FormProvider, FormField, Input } from '@hey-mike/tungsten';

// FormField always lives inside a FormProvider. Each variant wraps its own
// provider so the snapshot captures the field in isolation. We show the states
// FormField renders declaratively without interaction: default, with help text,
// and required (visible marker). The error state requires a failed submit, so
// it's covered by the unit tests + recipes rather than this static snapshot.
export default function FormFieldSnapshot() {
  return (
    <VariantGrid
      title="FormField"
      variants={[
        {
          label: 'default',
          node: (
            <FormProvider>
              <FormField name="email" label="Email">
                <Input placeholder="you@example.com" />
              </FormField>
            </FormProvider>
          ),
        },
        {
          label: 'with help',
          node: (
            <FormProvider>
              <FormField name="email" label="Email" help="We never share it.">
                <Input placeholder="you@example.com" />
              </FormField>
            </FormProvider>
          ),
        },
        {
          label: 'required',
          node: (
            <FormProvider>
              <FormField name="email" label="Email" required>
                <Input placeholder="you@example.com" />
              </FormField>
            </FormProvider>
          ),
        },
      ]}
    />
  );
}
import { VariantGrid } from '../_components/VariantGrid';
import { FormProvider, FormField, Input } from '@hey-mike/tungsten';

// FormField always lives inside a FormProvider. Each variant wraps its own
// provider so the snapshot captures the field in isolation. We show the states
// FormField renders declaratively without interaction: default, with help text,
// and required (visible marker). The error state requires a failed submit, so
// it's covered by the unit tests + recipes rather than this static snapshot.
export default function FormFieldSnapshot() {
  return (
    <VariantGrid
      title="FormField"
      variants={[
        {
          label: 'default',
          node: (
            <FormProvider>
              <FormField name="email" label="Email">
                <Input placeholder="you@example.com" />
              </FormField>
            </FormProvider>
          ),
        },
        {
          label: 'with help',
          node: (
            <FormProvider>
              <FormField name="email" label="Email" help="We never share it.">
                <Input placeholder="you@example.com" />
              </FormField>
            </FormProvider>
          ),
        },
        {
          label: 'required',
          node: (
            <FormProvider>
              <FormField name="email" label="Email" required>
                <Input placeholder="you@example.com" />
              </FormField>
            </FormProvider>
          ),
        },
      ]}
    />
  );
}

Props

Surface specific to <FormField />.

PropTypeDefaultDescription
name*stringField name — the key under which the value lives in the form.
labelReactNodeVisible label. Rendered above the control and wired via htmlFor.
helpReactNodeSecondary help text rendered below the control.
requiredbooleanMarks the field required: visible marker + aria-required on the control.
validate((value: unknown) => string)Per-field validation; returns an error string when invalid.
children*ReactNodeThe form control (Input, Select, Textarea, …).
classNamestring

Used in recipes

Compositions from the /recipes reference that use this component.

Source