or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced.mdfield-api.mdform-api.mdframework-integrations.mdhooks.mdindex.mdvalidation.md

field-api.mddocs/

0

# Field Management

1

2

The FieldApi class provides granular control over individual form fields, including validation, metadata tracking, and array field operations. It integrates seamlessly with the FormApi to maintain field state and coordinate validation.

3

4

## Capabilities

5

6

### FieldApi Class

7

8

Core field management class for individual form field state and operations.

9

10

```typescript { .api }

11

class FieldApi<

12

TParentData,

13

TName extends DeepKeys<TParentData>,

14

TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,

15

TOnMount extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,

16

TOnChange extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,

17

TOnChangeAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData> = undefined,

18

TOnBlur extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,

19

TOnBlurAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData> = undefined,

20

TOnSubmit extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,

21

TOnSubmitAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData> = undefined,

22

TOnDynamic extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,

23

TOnDynamicAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData> = undefined,

24

TFormOnMount extends undefined | FormValidateOrFn<TParentData> = undefined,

25

TFormOnChange extends undefined | FormValidateOrFn<TParentData> = undefined,

26

TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,

27

TFormOnBlur extends undefined | FormValidateOrFn<TParentData> = undefined,

28

TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,

29

TFormOnSubmit extends undefined | FormValidateOrFn<TParentData> = undefined,

30

TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,

31

TFormOnDynamic extends undefined | FormValidateOrFn<TParentData> = undefined,

32

TFormOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,

33

TFormOnServer extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,

34

TParentSubmitMeta = never,

35

> {

36

/** Store instance for reactive state management */

37

store: Store<FieldState<TData>>;

38

39

/** Current field state */

40

state: FieldState<TData>;

41

42

/** Field name/path in the form data structure */

43

name: TName;

44

45

/** Parent form API instance */

46

form: FormApi<TParentData, ...>;

47

48

/** Field configuration options */

49

options: FieldApiOptions<TParentData, TName, TData, ...>;

50

51

constructor(opts: FieldApiOptions<TParentData, TName, TData, ...>);

52

53

/**

54

* Mounts the field and runs mount validation

55

* @returns Cleanup function to unmount the field

56

*/

57

mount(): () => void;

58

59

/**

60

* Updates field options with new configuration

61

* @param opts - Partial field options to update

62

*/

63

update(

64

opts: FieldApiOptions<TParentData, TName, TData, ...>,

65

): void;

66

67

/**

68

* Gets the current field value

69

* @deprecated Use `field.state.value` instead

70

* @returns Current value of the field

71

*/

72

getValue(): TData;

73

74

/**

75

* Sets the field value

76

* @param updater - Function or value to set

77

* @param opts - Options to control metadata updates and validation

78

*/

79

setValue(

80

updater: Updater<TData>,

81

opts?: UpdateMetaOptions,

82

): void;

83

84

/**

85

* Gets the field metadata

86

* @returns Current field metadata

87

*/

88

getMeta(): FieldMeta<TData, ...>;

89

90

/**

91

* Sets the field metadata

92

* @param updater - Function or value to update metadata

93

*/

94

setMeta(

95

updater: Updater<FieldMeta<TData, ...>>,

96

): void;

97

98

/**

99

* Gets field information including instance and validation metadata

100

* @returns Field info object

101

*/

102

getInfo(): FieldInfo;

103

104

/**

105

* Pushes a value to the field (for array fields)

106

* @param value - Value to push

107

* @param opts - Options to control metadata updates and validation

108

*/

109

pushValue(

110

value: TData extends Array<infer U> ? U : never,

111

opts?: UpdateMetaOptions,

112

): void;

113

114

/**

115

* Inserts a value at a specific index (for array fields)

116

* @param index - Index at which to insert

117

* @param value - Value to insert

118

* @param opts - Options to control metadata updates and validation

119

*/

120

insertValue(

121

index: number,

122

value: TData extends Array<infer U> ? U : never,

123

opts?: UpdateMetaOptions,

124

): void;

125

126

/**

127

* Removes a value at a specific index (for array fields)

128

* @param index - Index to remove

129

* @param opts - Options to control metadata updates and validation

130

*/

131

removeValue(

132

index: number,

133

opts?: UpdateMetaOptions,

134

): void;

135

136

/**

137

* Replaces a value at a specific index (for array fields)

138

* @param index - Index to replace

139

* @param value - New value

140

* @param opts - Options to control metadata updates and validation

141

*/

142

replaceValue(

143

index: number,

144

value: TData extends Array<infer U> ? U : never,

145

opts?: UpdateMetaOptions,

146

): void;

147

148

/**

149

* Swaps two values in the array (for array fields)

150

* @param aIndex - First index

151

* @param bIndex - Second index

152

* @param opts - Options to control metadata updates and validation

153

*/

154

swapValues(

155

aIndex: number,

156

bIndex: number,

157

opts?: UpdateMetaOptions,

158

): void;

159

160

/**

161

* Moves a value from one index to another (for array fields)

162

* @param aIndex - Source index

163

* @param bIndex - Destination index

164

* @param opts - Options to control metadata updates and validation

165

*/

166

moveValue(

167

aIndex: number,

168

bIndex: number,

169

opts?: UpdateMetaOptions,

170

): void;

171

172

/**

173

* Clears all values from the field (for array fields)

174

* @param opts - Options to control metadata updates and validation

175

*/

176

clearValues(

177

opts?: UpdateMetaOptions,

178

): void;

179

180

/**

181

* Validates the field

182

* @param cause - Reason for validation

183

* @returns Promise that resolves to array of validation errors

184

*/

185

validate(

186

cause: ValidationCause,

187

): Promise<ValidationError[]>;

188

189

/**

190

* Updates the field's error map by merging with existing errors

191

* @param errorMap - Validation error map to merge

192

*/

193

setErrorMap(

194

errorMap: ValidationErrorMap<

195

UnwrapFieldValidateOrFn<TName, TOnMount, TFormOnMount>,

196

UnwrapFieldValidateOrFn<TName, TOnChange, TFormOnChange>,

197

UnwrapFieldAsyncValidateOrFn<TName, TOnChangeAsync, TFormOnChangeAsync>,

198

UnwrapFieldValidateOrFn<TName, TOnBlur, TFormOnBlur>,

199

UnwrapFieldAsyncValidateOrFn<TName, TOnBlurAsync, TFormOnBlurAsync>,

200

UnwrapFieldValidateOrFn<TName, TOnSubmit, TFormOnSubmit>,

201

UnwrapFieldAsyncValidateOrFn<TName, TOnSubmitAsync, TFormOnSubmitAsync>,

202

UnwrapFieldValidateOrFn<TName, TOnDynamic, TFormOnDynamic>,

203

UnwrapFieldAsyncValidateOrFn<TName, TOnDynamicAsync, TFormOnDynamicAsync>

204

>,

205

): void;

206

207

/**

208

* Parses field value with a Standard Schema without setting internal errors

209

* Useful for one-off validation checks without affecting field state

210

* @param schema - The Standard Schema to validate against

211

* @returns Validation error if any, undefined if valid

212

*/

213

parseValueWithSchema(

214

schema: StandardSchemaV1<TData, unknown>,

215

): ValidationError | undefined;

216

217

/**

218

* Async version of parseValueWithSchema

219

* Parses field value with a Standard Schema without setting internal errors

220

* @param schema - The Standard Schema to validate against

221

* @returns Promise resolving to validation error if any, undefined if valid

222

*/

223

parseValueWithSchemaAsync(

224

schema: StandardSchemaV1<TData, unknown>,

225

): Promise<ValidationError | undefined>;

226

227

/**

228

* Handles field value change

229

* @param updater - Function or value to set

230

*/

231

handleChange(

232

updater: Updater<TData>,

233

): void;

234

235

/**

236

* Handles field blur event

237

*/

238

handleBlur(): void;

239

}

240

```

241

242

### Field Component

243

244

React component for rendering fields with render prop pattern.

245

246

```typescript { .api }

247

/**

248

* A function component that takes field options and a render function as children

249

* Uses the useField hook internally to manage the field instance

250

*

251

* @param props.name - Field path in the form data structure

252

* @param props.validators - Field-level validators

253

* @param props.children - Render function that receives the field API

254

* @param props.defaultValue - Default value for the field

255

* @param props.asyncDebounceMs - Debounce time for async validation

256

* @param props.preserveValue - Whether to preserve value on unmount

257

* @param props.mode - Rendering mode ('value' | 'array')

258

* @returns ReactNode

259

*/

260

const Field: <

261

TParentData,

262

TName extends DeepKeys<TParentData>,

263

TData extends DeepValue<TParentData, TName>,

264

TOnMount extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,

265

TOnChange extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,

266

TOnChangeAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData> = undefined,

267

TOnBlur extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,

268

TOnBlurAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData> = undefined,

269

TOnSubmit extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,

270

TOnSubmitAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData> = undefined,

271

TOnDynamic extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,

272

TOnDynamicAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData> = undefined,

273

TFormOnMount extends undefined | FormValidateOrFn<TParentData> = undefined,

274

TFormOnChange extends undefined | FormValidateOrFn<TParentData> = undefined,

275

TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,

276

TFormOnBlur extends undefined | FormValidateOrFn<TParentData> = undefined,

277

TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,

278

TFormOnSubmit extends undefined | FormValidateOrFn<TParentData> = undefined,

279

TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,

280

TFormOnDynamic extends undefined | FormValidateOrFn<TParentData> = undefined,

281

TFormOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,

282

TFormOnServer extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,

283

TParentSubmitMeta = never,

284

>({

285

children,

286

...fieldOptions

287

}: FieldComponentProps<

288

TParentData,

289

TName,

290

TData,

291

TOnMount,

292

TOnChange,

293

TOnChangeAsync,

294

TOnBlur,

295

TOnBlurAsync,

296

TOnSubmit,

297

TOnSubmitAsync,

298

TOnDynamic,

299

TOnDynamicAsync,

300

TFormOnMount,

301

TFormOnChange,

302

TFormOnChangeAsync,

303

TFormOnBlur,

304

TFormOnBlurAsync,

305

TFormOnSubmit,

306

TFormOnSubmitAsync,

307

TFormOnDynamic,

308

TFormOnDynamicAsync,

309

TFormOnServer,

310

TParentSubmitMeta

311

>) => ReactNode;

312

```

313

314

### FieldOptions

315

316

Configuration options for creating a field instance.

317

318

```typescript { .api }

319

interface FieldOptions<

320

TParentData,

321

TName extends DeepKeys<TParentData>,

322

TData extends DeepValue<TParentData, TName>,

323

TOnMount extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

324

TOnChange extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

325

TOnChangeAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

326

TOnBlur extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

327

TOnBlurAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

328

TOnSubmit extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

329

TOnSubmitAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

330

TOnDynamic extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

331

TOnDynamicAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

332

> {

333

/** Field path in the form data structure (supports dot notation and array indices) */

334

name: TName;

335

336

/** Default value for the field */

337

defaultValue?: TData;

338

339

/** Debounce time in milliseconds for async validation */

340

asyncDebounceMs?: number;

341

342

/** Whether to always run async validation (even if sync validation fails) */

343

asyncAlways?: boolean;

344

345

/** Field-level validators */

346

validators?: FieldValidators<

347

TParentData,

348

TName,

349

TData,

350

TOnMount,

351

TOnChange,

352

TOnChangeAsync,

353

TOnBlur,

354

TOnBlurAsync,

355

TOnSubmit,

356

TOnSubmitAsync,

357

TOnDynamic,

358

TOnDynamicAsync

359

>;

360

361

/** Whether to preserve field value when unmounted */

362

preserveValue?: boolean;

363

}

364

365

interface FieldApiOptions<

366

TParentData,

367

TName extends DeepKeys<TParentData>,

368

TData extends DeepValue<TParentData, TName>,

369

TOnMount extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

370

TOnChange extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

371

TOnChangeAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

372

TOnBlur extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

373

TOnBlurAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

374

TOnSubmit extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

375

TOnSubmitAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

376

TOnDynamic extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

377

TOnDynamicAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

378

TFormOnMount extends undefined | FormValidateOrFn<TParentData>,

379

TFormOnChange extends undefined | FormValidateOrFn<TParentData>,

380

TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn<TParentData>,

381

TFormOnBlur extends undefined | FormValidateOrFn<TParentData>,

382

TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn<TParentData>,

383

TFormOnSubmit extends undefined | FormValidateOrFn<TParentData>,

384

TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TParentData>,

385

TFormOnDynamic extends undefined | FormValidateOrFn<TParentData>,

386

TFormOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TParentData>,

387

TFormOnServer extends undefined | FormAsyncValidateOrFn<TParentData>,

388

TParentSubmitMeta,

389

> extends FieldOptions<

390

TParentData,

391

TName,

392

TData,

393

TOnMount,

394

TOnChange,

395

TOnChangeAsync,

396

TOnBlur,

397

TOnBlurAsync,

398

TOnSubmit,

399

TOnSubmitAsync,

400

TOnDynamic,

401

TOnDynamicAsync

402

> {

403

/** Parent form API instance */

404

form: FormApi<

405

TParentData,

406

TFormOnMount,

407

TFormOnChange,

408

TFormOnChangeAsync,

409

TFormOnBlur,

410

TFormOnBlurAsync,

411

TFormOnSubmit,

412

TFormOnSubmitAsync,

413

TFormOnDynamic,

414

TFormOnDynamicAsync,

415

TFormOnServer,

416

TParentSubmitMeta

417

>;

418

}

419

```

420

421

### UseFieldOptions

422

423

React hook-specific field options with mode support.

424

425

```typescript { .api }

426

interface UseFieldOptions<

427

TParentData,

428

TName extends DeepKeys<TParentData>,

429

TData extends DeepValue<TParentData, TName>,

430

TOnMount extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

431

TOnChange extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

432

TOnChangeAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

433

TOnBlur extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

434

TOnBlurAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

435

TOnSubmit extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

436

TOnSubmitAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

437

TOnDynamic extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

438

TOnDynamicAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

439

TFormOnMount extends undefined | FormValidateOrFn<TParentData>,

440

TFormOnChange extends undefined | FormValidateOrFn<TParentData>,

441

TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn<TParentData>,

442

TFormOnBlur extends undefined | FormValidateOrFn<TParentData>,

443

TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn<TParentData>,

444

TFormOnSubmit extends undefined | FormValidateOrFn<TParentData>,

445

TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TParentData>,

446

TFormOnDynamic extends undefined | FormValidateOrFn<TParentData>,

447

TFormOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TParentData>,

448

TFormOnServer extends undefined | FormAsyncValidateOrFn<TParentData>,

449

TSubmitMeta,

450

> extends FieldApiOptions<

451

TParentData,

452

TName,

453

TData,

454

TOnMount,

455

TOnChange,

456

TOnChangeAsync,

457

TOnBlur,

458

TOnBlurAsync,

459

TOnSubmit,

460

TOnSubmitAsync,

461

TOnDynamic,

462

TOnDynamicAsync,

463

TFormOnMount,

464

TFormOnChange,

465

TFormOnChangeAsync,

466

TFormOnBlur,

467

TFormOnBlurAsync,

468

TFormOnSubmit,

469

TFormOnSubmitAsync,

470

TFormOnDynamic,

471

TFormOnDynamicAsync,

472

TFormOnServer,

473

TSubmitMeta

474

> {

475

/**

476

* Rendering mode for the field

477

* - 'value': Standard value mode (default) - field re-renders on every value change

478

* - 'array': Array mode with optimized re-rendering - use for array fields to prevent unnecessary re-renders of sibling array items when one item changes

479

*

480

* When using 'array' mode with array fields, child fields will only re-render when their specific index changes,

481

* rather than re-rendering all items when any item in the array changes. This significantly improves performance

482

* for forms with dynamic arrays of fields.

483

*

484

* Example usage:

485

* ```typescript

486

* <form.Field name="todos" mode="array">

487

* {(field) => (

488

* <div>

489

* {field.state.value.map((_, index) => (

490

* <form.Field key={index} name={`todos[${index}].text`}>

491

* {(subField) => <input value={subField.state.value} />}

492

* </form.Field>

493

* ))}

494

* </div>

495

* )}

496

* </form.Field>

497

* ```

498

*/

499

mode?: 'value' | 'array';

500

}

501

502

interface UseFieldOptionsBound<

503

TParentData,

504

TName extends DeepKeys<TParentData>,

505

TData extends DeepValue<TParentData, TName>,

506

TOnMount extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

507

TOnChange extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

508

TOnChangeAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

509

TOnBlur extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

510

TOnBlurAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

511

TOnSubmit extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

512

TOnSubmitAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

513

TOnDynamic extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

514

TOnDynamicAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

515

> extends FieldOptions<

516

TParentData,

517

TName,

518

TData,

519

TOnMount,

520

TOnChange,

521

TOnChangeAsync,

522

TOnBlur,

523

TOnBlurAsync,

524

TOnSubmit,

525

TOnSubmitAsync,

526

TOnDynamic,

527

TOnDynamicAsync

528

> {

529

/** Rendering mode for the field */

530

mode?: 'value' | 'array';

531

}

532

```

533

534

### FieldState

535

536

Complete field state including value and metadata.

537

538

```typescript { .api }

539

interface FieldState<TData> {

540

/** Current field value */

541

value: TData;

542

543

/** Field metadata (base + derived) */

544

meta: FieldMeta<TData, any, any, ...>;

545

}

546

547

type FieldMeta<TData, ...> = FieldMetaBase<TData, ...> & FieldMetaDerived<TData, ...>;

548

549

interface FieldMetaBase<TData, ...> {

550

/** Whether the field has been touched (focused and then blurred) */

551

isTouched: boolean;

552

553

/** Whether the field has been blurred */

554

isBlurred: boolean;

555

556

/** Whether the field has been modified from its initial value */

557

isDirty: boolean;

558

559

/** Map of errors by validation trigger type */

560

errorMap: ValidationErrorMap;

561

562

/** Map tracking the source of errors (private) */

563

errorSourceMap: ValidationErrorMapSource;

564

565

/** Whether validation is currently in progress */

566

isValidating: boolean;

567

}

568

569

interface FieldMetaDerived<TData, ...> {

570

/** Array of validation errors for the field */

571

errors: ValidationError[];

572

573

/**

574

* Array of validation errors only shown after field has been touched/blurred

575

* This property may be undefined until the field has been interacted with

576

*/

577

touchedErrors?: ValidationError[];

578

579

/** Whether the field is in its initial state */

580

isPristine: boolean;

581

582

/** Whether the field is valid (no errors) */

583

isValid: boolean;

584

585

/** Whether the field's current value is the default value */

586

isDefaultValue: boolean;

587

}

588

589

/** Type representing any FieldMeta */

590

type AnyFieldMeta = FieldMeta<any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any>;

591

```

592

593

### FieldValidators

594

595

Field-level validator configuration.

596

597

```typescript { .api }

598

interface FieldValidators<

599

TParentData,

600

TName extends DeepKeys<TParentData>,

601

TData extends DeepValue<TParentData, TName>,

602

TOnMount extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

603

TOnChange extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

604

TOnChangeAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

605

TOnBlur extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

606

TOnBlurAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

607

TOnSubmit extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

608

TOnSubmitAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

609

TOnDynamic extends undefined | FieldValidateOrFn<TParentData, TName, TData>,

610

TOnDynamicAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData>,

611

> {

612

/** Validator that runs when field is mounted */

613

onMount?: TOnMount;

614

615

/** Validator that runs when field value changes */

616

onChange?: TOnChange;

617

618

/** Async validator that runs when field value changes */

619

onChangeAsync?: TOnChangeAsync;

620

621

/** Validator that runs when field is blurred */

622

onBlur?: TOnBlur;

623

624

/** Async validator that runs when field is blurred */

625

onBlurAsync?: TOnBlurAsync;

626

627

/** Validator that runs on form submission */

628

onSubmit?: TOnSubmit;

629

630

/** Async validator that runs on form submission */

631

onSubmitAsync?: TOnSubmitAsync;

632

633

/** Validator that runs dynamically based on validation logic */

634

onDynamic?: TOnDynamic;

635

636

/** Async validator that runs dynamically based on validation logic */

637

onDynamicAsync?: TOnDynamicAsync;

638

639

/**

640

* Array of field paths to listen to for changes

641

* When any of these fields change, this field's onChange/onChangeAsync validators run

642

*/

643

onChangeListenTo?: DeepKeys<TParentData>[];

644

645

/**

646

* Array of field paths to listen to for blur events

647

* When any of these fields blur, this field's onBlur/onBlurAsync validators run

648

*/

649

onBlurListenTo?: DeepKeys<TParentData>[];

650

}

651

```

652

653

### FieldListeners

654

655

Event listener configuration for field lifecycle events.

656

657

```typescript { .api }

658

interface FieldListeners<

659

TParentData,

660

TName extends DeepKeys<TParentData>,

661

TData extends DeepValue<TParentData, TName>,

662

...

663

> {

664

/**

665

* Listener called when field is mounted

666

* @param fieldApi - Field API instance

667

*/

668

onMount?: (

669

fieldApi: FieldApi<TParentData, TName, TData, ...>,

670

) => void;

671

672

/**

673

* Listener called when field value changes

674

* @param fieldApi - Field API instance

675

*/

676

onChange?: (

677

fieldApi: FieldApi<TParentData, TName, TData, ...>,

678

) => void;

679

680

/**

681

* Listener called when field is blurred

682

* @param fieldApi - Field API instance

683

*/

684

onBlur?: (

685

fieldApi: FieldApi<TParentData, TName, TData, ...>,

686

) => void;

687

688

/**

689

* Listener called on form submission

690

* @param fieldApi - Field API instance

691

*/

692

onSubmit?: (

693

fieldApi: FieldApi<TParentData, TName, TData, ...>,

694

) => void;

695

}

696

```

697

698

### Field Validation Types

699

700

```typescript { .api }

701

/**

702

* Synchronous field validation function

703

* @param props.value - Current field value

704

* @param props.fieldApi - Field API instance

705

* @returns Validation error or undefined if valid

706

*/

707

type FieldValidateFn<TParentData, TName, TData> = (props: {

708

value: TData;

709

fieldApi: FieldApi<TParentData, TName, TData, ...>;

710

}) => ValidationError | Promise<ValidationError>;

711

712

/**

713

* Asynchronous field validation function with abort signal support

714

* @param props.value - Current field value

715

* @param props.signal - AbortSignal for cancellation

716

* @param props.fieldApi - Field API instance

717

* @returns Promise resolving to validation error or undefined if valid

718

*/

719

type FieldValidateAsyncFn<TParentData, TName, TData> = (props: {

720

value: TData;

721

signal: AbortSignal;

722

fieldApi: FieldApi<TParentData, TName, TData, ...>;

723

}) => ValidationError | Promise<ValidationError>;

724

725

/** Union of validation function or Standard Schema validator */

726

type FieldValidateOrFn<TParentData, TName, TData> =

727

| FieldValidateFn<TParentData, TName, TData>

728

| StandardSchemaV1<TData, TData>;

729

730

/** Union of async validation function or Standard Schema validator */

731

type FieldAsyncValidateOrFn<TParentData, TName, TData> =

732

| FieldValidateAsyncFn<TParentData, TName, TData>

733

| StandardSchemaV1<TData, TData>;

734

```

735

736

### Helper Types

737

738

```typescript { .api }

739

/** Type representing any FieldApi instance */

740

type AnyFieldApi = FieldApi<any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any>;

741

742

/** Options for controlling metadata and validation updates */

743

interface UpdateMetaOptions {

744

/** Skip metadata update */

745

dontUpdateMeta?: boolean;

746

747

/** Skip validation after update */

748

dontValidate?: boolean;

749

750

/** Skip running listeners */

751

dontRunListeners?: boolean;

752

}

753

```

754

755

## Helper Types

756

757

Type aliases for convenience when working with fields without needing to specify all generic parameters.

758

759

```typescript { .api }

760

/**

761

* FieldApi with all generics set to any for convenience in dynamic or loosely-typed contexts

762

* Useful when you need to work with fields of unknown structure

763

*/

764

type AnyFieldApi = FieldApi<any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any>;

765

766

/**

767

* FieldMeta with all generics set to any for convenience

768

* Useful for generic field metadata handling

769

*/

770

type AnyFieldMeta = FieldMeta<any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any>;

771

```

772

773

## Usage Examples

774

775

### Basic Field with Validation

776

777

```typescript

778

import { useForm } from '@tanstack/react-form';

779

780

function MyForm() {

781

const form = useForm({

782

defaultValues: {

783

email: '',

784

},

785

});

786

787

return (

788

<form.Field

789

name="email"

790

validators={{

791

onChange: ({ value }) => {

792

if (!value.includes('@')) {

793

return 'Invalid email address';

794

}

795

return undefined;

796

},

797

onChangeAsync: async ({ value, signal }) => {

798

// Check email availability with server

799

const response = await fetch(`/api/check-email?email=${value}`, { signal });

800

const data = await response.json();

801

return data.available ? undefined : 'Email already registered';

802

},

803

}}

804

>

805

{(field) => (

806

<div>

807

<label htmlFor={field.name}>Email:</label>

808

<input

809

id={field.name}

810

value={field.state.value}

811

onChange={(e) => field.handleChange(e.target.value)}

812

onBlur={field.handleBlur}

813

/>

814

{field.state.meta.isTouched && field.state.meta.errors.length > 0 && (

815

<em>{field.state.meta.errors[0]}</em>

816

)}

817

{field.state.meta.isValidating && <span>Validating...</span>}

818

</div>

819

)}

820

</form.Field>

821

);

822

}

823

```

824

825

### Array Field with Dynamic Items

826

827

```typescript

828

function TodoListForm() {

829

const form = useForm({

830

defaultValues: {

831

todos: [{ text: '', completed: false }],

832

},

833

});

834

835

return (

836

<form.Field name="todos" mode="array">

837

{(field) => (

838

<div>

839

{field.state.value.map((_, index) => (

840

<form.Field key={index} name={`todos[${index}].text`}>

841

{(subField) => (

842

<div>

843

<input

844

value={subField.state.value}

845

onChange={(e) => subField.handleChange(e.target.value)}

846

/>

847

<button

848

type="button"

849

onClick={() => field.removeValue(index)}

850

>

851

Remove

852

</button>

853

</div>

854

)}

855

</form.Field>

856

))}

857

<button

858

type="button"

859

onClick={() => field.pushValue({ text: '', completed: false })}

860

>

861

Add Todo

862

</button>

863

</div>

864

)}

865

</form.Field>

866

);

867

}

868

```

869

870

### Field with Cross-Field Validation

871

872

```typescript

873

function PasswordForm() {

874

const form = useForm({

875

defaultValues: {

876

password: '',

877

confirmPassword: '',

878

},

879

});

880

881

return (

882

<>

883

<form.Field name="password">

884

{(field) => (

885

<input

886

type="password"

887

value={field.state.value}

888

onChange={(e) => field.handleChange(e.target.value)}

889

/>

890

)}

891

</form.Field>

892

893

<form.Field

894

name="confirmPassword"

895

validators={{

896

onChangeListenTo: ['password'],

897

onChange: ({ value, fieldApi }) => {

898

const password = fieldApi.form.getFieldValue('password');

899

if (value !== password) {

900

return 'Passwords do not match';

901

}

902

return undefined;

903

},

904

}}

905

>

906

{(field) => (

907

<div>

908

<input

909

type="password"

910

value={field.state.value}

911

onChange={(e) => field.handleChange(e.target.value)}

912

/>

913

{field.state.meta.errors[0] && (

914

<em>{field.state.meta.errors[0]}</em>

915

)}

916

</div>

917

)}

918

</form.Field>

919

</>

920

);

921

}

922

```

923

924

### Using useField Hook Directly

925

926

```typescript

927

import { useForm, useField } from '@tanstack/react-form';

928

929

function EmailInput() {

930

const form = useForm({

931

defaultValues: {

932

email: '',

933

},

934

});

935

936

const emailField = useField({

937

form,

938

name: 'email',

939

validators: {

940

onChange: ({ value }) => {

941

if (!value.includes('@')) {

942

return 'Invalid email';

943

}

944

return undefined;

945

},

946

},

947

});

948

949

return (

950

<div>

951

<input

952

value={emailField.state.value}

953

onChange={(e) => emailField.handleChange(e.target.value)}

954

onBlur={emailField.handleBlur}

955

/>

956

{emailField.state.meta.isTouched && emailField.state.meta.errors[0]}

957

</div>

958

);

959

}

960

```

961