or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

field.mdform-spy.mdform.mdhooks.mdindex.mdtypescript.md

hooks.mddocs/

0

# Hooks API

1

2

Modern React hooks for accessing form context, field state, and form state with customizable subscriptions and full TypeScript support.

3

4

## Capabilities

5

6

### useForm Hook

7

8

Hook to access the form API from within form components and field components.

9

10

```typescript { .api }

11

/**

12

* Hook to access form API from React context

13

* @param componentName - Optional component name for error messages

14

* @returns Form API instance

15

* @throws Error if used outside of Form component

16

*/

17

function useForm<FormValues = Record<string, any>>(

18

componentName?: string

19

): FormApi<FormValues>;

20

```

21

22

**Usage Examples:**

23

24

```typescript

25

import React from "react";

26

import { Form, useForm } from "react-final-form";

27

28

// Basic useForm usage

29

function CustomFormButton() {

30

const form = useForm();

31

32

return (

33

<button

34

type="button"

35

onClick={() => form.reset()}

36

>

37

Reset Form

38

</button>

39

);

40

}

41

42

// useForm with component name for better error messages

43

function CustomField() {

44

const form = useForm("CustomField");

45

46

const handleSetValue = () => {

47

form.change("myField", "new value");

48

};

49

50

return (

51

<div>

52

<button onClick={handleSetValue}>Set Value</button>

53

<button onClick={() => form.focus("myField")}>Focus Field</button>

54

</div>

55

);

56

}

57

58

// Using form API for programmatic control

59

function FormControls() {

60

const form = useForm();

61

62

const handleBatch = () => {

63

form.batch(() => {

64

form.change("firstName", "John");

65

form.change("lastName", "Doe");

66

form.change("email", "john.doe@example.com");

67

});

68

};

69

70

return (

71

<div>

72

<button onClick={handleBatch}>Fill Form</button>

73

<button onClick={() => form.restart()}>Restart</button>

74

<button onClick={() => form.reset()}>Reset</button>

75

</div>

76

);

77

}

78

79

// Complete form example with useForm

80

function MyForm() {

81

return (

82

<Form onSubmit={(values) => console.log(values)}>

83

{({ handleSubmit }) => (

84

<form onSubmit={handleSubmit}>

85

<input name="firstName" />

86

<CustomFormButton />

87

</form>

88

)}

89

</Form>

90

);

91

}

92

```

93

94

### useField Hook

95

96

Hook for field-level state management that returns field input props and metadata.

97

98

```typescript { .api }

99

/**

100

* Hook for field state management and input props

101

* @param name - Field name (required)

102

* @param config - Field configuration options

103

* @returns Field render props with input and meta

104

*/

105

function useField<

106

FieldValue = any,

107

T extends HTMLElement = HTMLElement,

108

FormValues = Record<string, any>

109

>(

110

name: string,

111

config?: UseFieldConfig

112

): FieldRenderProps<FieldValue, T, FormValues>;

113

114

interface UseFieldConfig extends UseFieldAutoConfig {

115

/** Field state subscription configuration */

116

subscription?: FieldSubscription;

117

}

118

119

interface FieldRenderProps<

120

FieldValue = any,

121

T extends HTMLElement = HTMLElement,

122

FormValues = any

123

> {

124

/** Input props to spread on form elements */

125

input: FieldInputProps<FieldValue, T>;

126

/** Field metadata and state information */

127

meta: FieldMeta;

128

}

129

```

130

131

**Usage Examples:**

132

133

```typescript

134

import React from "react";

135

import { Form, useField } from "react-final-form";

136

137

// Basic useField usage

138

function CustomTextField({ name, ...props }: { name: string }) {

139

const { input, meta } = useField(name);

140

141

return (

142

<div>

143

<input {...input} {...props} />

144

{meta.error && meta.touched && <span>{meta.error}</span>}

145

</div>

146

);

147

}

148

149

// useField with validation

150

function ValidatedInput({ name, validate, ...props }: any) {

151

const { input, meta } = useField(name, { validate });

152

153

return (

154

<div className={meta.error ? "error" : ""}>

155

<input {...input} {...props} />

156

{meta.error && meta.touched && (

157

<div className="error-message">{meta.error}</div>

158

)}

159

{meta.validating && <div className="validating">Validating...</div>}

160

</div>

161

);

162

}

163

164

// useField with formatting and parsing

165

function CurrencyInput({ name }: { name: string }) {

166

const format = (value: number) => {

167

if (value === undefined) return "";

168

return `$${value.toFixed(2)}`;

169

};

170

171

const parse = (value: string) => {

172

const number = parseFloat(value.replace(/[^0-9.-]/g, ""));

173

return isNaN(number) ? undefined : number;

174

};

175

176

const { input, meta } = useField(name, { format, parse });

177

178

return (

179

<div>

180

<input {...input} type="text" placeholder="$0.00" />

181

{meta.error && meta.touched && <span>{meta.error}</span>}

182

</div>

183

);

184

}

185

186

// useField with subscription optimization

187

function OptimizedField({ name }: { name: string }) {

188

const { input, meta } = useField(name, {

189

subscription: { value: true, error: true, touched: true }

190

});

191

192

return (

193

<div>

194

<input {...input} />

195

{meta.error && meta.touched && <span>{meta.error}</span>}

196

</div>

197

);

198

}

199

200

// Custom checkbox component

201

function CustomCheckbox({ name, label }: { name: string; label: string }) {

202

const { input, meta } = useField(name, { type: "checkbox" });

203

204

return (

205

<label>

206

<input {...input} type="checkbox" />

207

{label}

208

</label>

209

);

210

}

211

212

// Form using custom field components

213

function MyForm() {

214

const required = (value: any) => (value ? undefined : "Required");

215

216

return (

217

<Form onSubmit={(values) => console.log(values)}>

218

{({ handleSubmit }) => (

219

<form onSubmit={handleSubmit}>

220

<CustomTextField name="firstName" placeholder="First Name" />

221

<ValidatedInput

222

name="email"

223

type="email"

224

validate={required}

225

placeholder="Email"

226

/>

227

<CurrencyInput name="salary" />

228

<CustomCheckbox name="subscribe" label="Subscribe to newsletter" />

229

<button type="submit">Submit</button>

230

</form>

231

)}

232

</Form>

233

);

234

}

235

```

236

237

### useFormState Hook

238

239

Hook for subscribing to form state changes with customizable subscriptions.

240

241

```typescript { .api }

242

/**

243

* Hook for form state subscription with performance optimization

244

* @param params - Configuration for form state subscription

245

* @returns Current form state based on subscription

246

*/

247

function useFormState<FormValues = Record<string, any>>(

248

params?: UseFormStateParams<FormValues>

249

): FormState<FormValues>;

250

251

interface UseFormStateParams<FormValues = Record<string, any>> {

252

/** Callback when form state changes */

253

onChange?: (formState: FormState<FormValues>) => void;

254

/** Form state subscription configuration */

255

subscription?: FormSubscription;

256

}

257

```

258

259

**Usage Examples:**

260

261

```typescript

262

import React from "react";

263

import { Form, Field, useFormState } from "react-final-form";

264

265

// Basic useFormState usage

266

function FormStatus() {

267

const { dirty, invalid, submitting } = useFormState();

268

269

return (

270

<div>

271

<p>Form is {dirty ? "dirty" : "pristine"}</p>

272

<p>Form is {invalid ? "invalid" : "valid"}</p>

273

{submitting && <p>Submitting...</p>}

274

</div>

275

);

276

}

277

278

// useFormState with subscription

279

function OptimizedFormStatus() {

280

const { submitting, pristine, invalid } = useFormState({

281

subscription: { submitting: true, pristine: true, invalid: true }

282

});

283

284

return (

285

<button type="submit" disabled={submitting || pristine || invalid}>

286

{submitting ? "Submitting..." : "Submit"}

287

</button>

288

);

289

}

290

291

// useFormState with onChange callback

292

function FormMonitor() {

293

const formState = useFormState({

294

onChange: (state) => {

295

console.log("Form state changed:", state);

296

// Auto-save, analytics, etc.

297

}

298

});

299

300

return (

301

<div>

302

<h3>Form Monitor</h3>

303

<pre>{JSON.stringify(formState, null, 2)}</pre>

304

</div>

305

);

306

}

307

308

// useFormState for conditional rendering

309

function ConditionalFields() {

310

const { values } = useFormState({ subscription: { values: true } });

311

312

return (

313

<div>

314

{values.showAdvanced && (

315

<div>

316

<Field name="advancedOption1" component="input" />

317

<Field name="advancedOption2" component="input" />

318

</div>

319

)}

320

</div>

321

);

322

}

323

324

// Complete form with hooks

325

function HookBasedForm() {

326

return (

327

<Form onSubmit={(values) => console.log(values)}>

328

{({ handleSubmit }) => (

329

<form onSubmit={handleSubmit}>

330

<Field name="name" component="input" placeholder="Name" />

331

<Field name="showAdvanced" component="input" type="checkbox" />

332

333

<ConditionalFields />

334

<FormStatus />

335

<FormMonitor />

336

337

<button type="submit">Submit</button>

338

</form>

339

)}

340

</Form>

341

);

342

}

343

```

344

345

### Hook Configuration Options

346

347

All hooks support comprehensive configuration options for optimization and customization.

348

349

```typescript { .api }

350

/**

351

* Field subscription configuration for useField hook

352

*/

353

interface FieldSubscription {

354

active?: boolean;

355

data?: boolean;

356

dirty?: boolean;

357

dirtySinceLastSubmit?: boolean;

358

error?: boolean;

359

initial?: boolean;

360

invalid?: boolean;

361

length?: boolean;

362

modified?: boolean;

363

modifiedSinceLastSubmit?: boolean;

364

pristine?: boolean;

365

submitError?: boolean;

366

submitFailed?: boolean;

367

submitSucceeded?: boolean;

368

submitting?: boolean;

369

touched?: boolean;

370

valid?: boolean;

371

validating?: boolean;

372

value?: boolean;

373

visited?: boolean;

374

}

375

376

/**

377

* Form subscription configuration for useFormState hook

378

*/

379

interface FormSubscription {

380

active?: boolean;

381

dirty?: boolean;

382

dirtyFields?: boolean;

383

dirtySinceLastSubmit?: boolean;

384

error?: boolean;

385

errors?: boolean;

386

hasSubmitErrors?: boolean;

387

hasValidationErrors?: boolean;

388

initialValues?: boolean;

389

invalid?: boolean;

390

modified?: boolean;

391

modifiedSinceLastSubmit?: boolean;

392

pristine?: boolean;

393

submitError?: boolean;

394

submitErrors?: boolean;

395

submitFailed?: boolean;

396

submitSucceeded?: boolean;

397

submitting?: boolean;

398

touched?: boolean;

399

valid?: boolean;

400

validating?: boolean;

401

values?: boolean;

402

visited?: boolean;

403

}

404

```

405

406

### Hook Error Handling

407

408

Hooks provide clear error messages when used incorrectly.

409

410

**Usage Examples:**

411

412

```typescript

413

// Error handling example

414

function SafeHookUsage() {

415

try {

416

const form = useForm("SafeComponent");

417

return <div>Form API available</div>;

418

} catch (error) {

419

return <div>Error: Component must be used inside a Form</div>;

420

}

421

}

422

423

// Conditional hook usage (NOT RECOMMENDED - breaks rules of hooks)

424

// Instead, always use hooks at the top level and handle conditions in render

425

function CorrectConditionalUsage() {

426

const form = useForm(); // Always call hooks at top level

427

const { values } = useFormState();

428

429

if (!values.needsField) {

430

return <div>Field not needed</div>;

431

}

432

433

// Use hook results conditionally, not the hooks themselves

434

return (

435

<div>

436

<button onClick={() => form.reset()}>Reset</button>

437

</div>

438

);

439

}

440

```

441

442

### Performance Optimization with Hooks

443

444

Hooks support performance optimization through subscriptions and memoization.

445

446

**Usage Examples:**

447

448

```typescript

449

import React from "react";

450

451

// Optimized field component

452

function OptimizedField({ name }: { name: string }) {

453

const { input, meta } = useField(name, {

454

subscription: { value: true, error: true, touched: true }

455

});

456

457

return React.useMemo(() => (

458

<div>

459

<input {...input} />

460

{meta.error && meta.touched && <span>{meta.error}</span>}

461

</div>

462

), [input.value, meta.error, meta.touched]);

463

}

464

465

// Memoized form status component

466

const FormStatusMemo = React.memo(() => {

467

const { dirty, invalid, submitting } = useFormState({

468

subscription: { dirty: true, invalid: true, submitting: true }

469

});

470

471

return (

472

<div>

473

Status: {dirty ? "Modified" : "Unchanged"} |

474

{invalid ? "Invalid" : "Valid"} |

475

{submitting ? "Submitting" : "Ready"}

476

</div>

477

);

478

});

479

```