or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration-rules.mdcore-validation.mdfield-management.mdform-actions.mdform-management.mdindex.mdstate-access.mdvue-components.md

form-management.mddocs/

0

# Form Management

1

2

Form-level composables for managing complete form state, validation, submission handling, and providing context to child components. These composables are the foundation for building complex forms with VeeValidate.

3

4

## Capabilities

5

6

### useForm Composable

7

8

Creates a form context with comprehensive validation management and state tracking.

9

10

```typescript { .api }

11

/**

12

* Creates a form context with validation management

13

* @param options - Optional form configuration

14

* @returns Form context object with state and methods

15

*/

16

function useForm<TValues extends GenericObject = GenericObject, TOutput extends GenericObject = TValues>(

17

options?: FormOptions<TValues>

18

): FormContext<TValues, TOutput>;

19

20

interface FormOptions<TValues extends GenericObject> {

21

validationSchema?: MaybeRef<RawFormSchema<TValues> | TypedSchema<TValues, TOutput> | YupSchema<TValues> | undefined>;

22

initialValues?: PartialDeep<TValues>;

23

initialErrors?: Partial<FlattenAndSetPathsType<TValues, string | string[] | undefined>>;

24

initialTouched?: Partial<FlattenAndSetPathsType<TValues, boolean>>;

25

validateOnMount?: boolean;

26

keepValuesOnUnmount?: MaybeRef<boolean>;

27

name?: string;

28

}

29

30

interface FormContext<TValues extends GenericObject = GenericObject, TOutput extends GenericObject = TValues> {

31

// Form state

32

values: TValues;

33

errors: ComputedRef<FormErrors<TValues>>;

34

meta: ComputedRef<FormMeta<TValues>>;

35

isSubmitting: Ref<boolean>;

36

isValidating: Ref<boolean>;

37

submitCount: Ref<number>;

38

controlledValues: Ref<TValues>;

39

40

// Form methods

41

handleSubmit: HandleSubmitFactory<TValues, TOutput> & { withControlled: HandleSubmitFactory<TValues, TOutput> };

42

validate(opts?: Partial<ValidationOptions>): Promise<FormValidationResult<TValues, TOutput>>;

43

validateField<TPath extends Path<TValues>>(field: TPath, opts?: Partial<ValidationOptions>): Promise<ValidationResult<TOutput[TPath]>>;

44

45

// State mutations

46

setFieldValue<T extends Path<TValues>>(field: T, value: PathValue<TValues, T>, shouldValidate?: boolean): void;

47

setFieldError(field: Path<TValues>, message: string | string[] | undefined): void;

48

setErrors(fields: Partial<FlattenAndSetPathsType<TValues, string | string[] | undefined>>): void;

49

setValues(fields: PartialDeep<TValues>, shouldValidate?: boolean): void;

50

setFieldTouched(field: Path<TValues>, isTouched: boolean): void;

51

setTouched(fields: Partial<Record<Path<TValues>, boolean>> | boolean): void;

52

resetForm(state?: Partial<FormState<TValues>>, opts?: Partial<ResetFormOpts>): void;

53

resetField(field: Path<TValues>, state?: Partial<FieldState>): void;

54

55

// Form context methods

56

handleReset(): void;

57

submitForm(e?: unknown): Promise<void>;

58

createPathState<TPath extends Path<TValues>>(path: MaybeRef<TPath>, config?: Partial<PathStateConfig<TOutput[TPath]>>): PathState<PathValue<TValues, TPath>>;

59

defineField<TPath extends Path<TValues>, TValue = PathValue<TValues, TPath>, TExtras extends GenericObject = GenericObject>(

60

path: MaybeRefOrGetter<TPath>,

61

config?: Partial<InputBindsConfig<TValue, TExtras>> | LazyInputBindsConfig<TValue, TExtras>

62

): [Ref<TValue>, Ref<BaseFieldProps & TExtras>];

63

}

64

65

type HandleSubmitFactory<TValues extends GenericObject, TOutput extends GenericObject = TValues> = <TReturn = unknown>(

66

cb: SubmissionHandler<TValues, TOutput, TReturn>,

67

onSubmitValidationErrorCb?: InvalidSubmissionHandler<TValues, TOutput>

68

) => (e?: Event) => Promise<TReturn | undefined>;

69

```

70

71

**Usage Examples:**

72

73

```typescript

74

import { useForm } from "vee-validate";

75

import * as yup from "yup";

76

77

// Basic form setup

78

const { handleSubmit, errors, meta, values } = useForm();

79

80

// Form with validation schema

81

const schema = yup.object({

82

name: yup.string().required("Name is required"),

83

email: yup.string().email("Email is invalid").required("Email is required"),

84

age: yup.number().min(18, "Must be at least 18").required("Age is required")

85

});

86

87

const {

88

handleSubmit,

89

errors,

90

meta,

91

values,

92

setFieldValue,

93

resetForm

94

} = useForm({

95

validationSchema: schema,

96

initialValues: {

97

name: "",

98

email: "",

99

age: 0

100

}

101

});

102

103

// Handle form submission

104

const onSubmit = handleSubmit((values) => {

105

console.log("Form submitted:", values);

106

// Submit to API

107

}, (ctx) => {

108

console.log("Form validation failed:", ctx.errors);

109

});

110

111

// Programmatic field manipulation

112

const updateUser = () => {

113

setFieldValue("name", "John Doe");

114

setFieldValue("email", "john@example.com");

115

};

116

117

// Reset form to initial state

118

const handleReset = () => {

119

resetForm();

120

};

121

122

// Advanced form with custom validation

123

const {

124

handleSubmit,

125

validate,

126

validateField,

127

setErrors

128

} = useForm({

129

validationSchema: {

130

username: (value) => {

131

if (!value) return "Username is required";

132

if (value.length < 3) return "Username too short";

133

return true;

134

},

135

password: (value) => {

136

if (!value) return "Password is required";

137

if (value.length < 8) return "Password must be at least 8 characters";

138

return true;

139

},

140

confirmPassword: (value, { form }) => {

141

if (!value) return "Please confirm password";

142

if (value !== form.password) return "Passwords do not match";

143

return true;

144

}

145

}

146

});

147

148

// Manual validation

149

const validateForm = async () => {

150

const result = await validate();

151

if (!result.valid) {

152

console.log("Form is invalid:", result.errors);

153

}

154

};

155

156

// Validate specific field

157

const validateUsername = async () => {

158

const result = await validateField("username");

159

if (!result.valid) {

160

console.log("Username is invalid:", result.errors);

161

}

162

};

163

```

164

165

### useFormContext Composable

166

167

Accesses the current form context via dependency injection from a parent Form component or useForm call.

168

169

```typescript { .api }

170

/**

171

* Accesses the current form context via dependency injection

172

* @returns Form context from nearest parent Form component or useForm call

173

* @throws Error if no form context is found

174

*/

175

function useFormContext<TValues extends GenericObject = GenericObject, TOutput extends GenericObject = TValues>(): FormContext<TValues, TOutput>;

176

```

177

178

**Usage Examples:**

179

180

```typescript

181

import { useFormContext } from "vee-validate";

182

183

// In a child component that needs access to form context

184

const ChildComponent = {

185

setup() {

186

const form = useFormContext();

187

188

// Access form state

189

const isFormValid = computed(() => form.meta.value.valid);

190

const formErrors = computed(() => form.errors.value);

191

192

// Use form methods

193

const clearForm = () => {

194

form.resetForm();

195

};

196

197

const submitForm = async () => {

198

const result = await form.validate();

199

if (result.valid) {

200

// Handle submission

201

}

202

};

203

204

return {

205

isFormValid,

206

formErrors,

207

clearForm,

208

submitForm

209

};

210

}

211

};

212

```

213

214

## Form State Types

215

216

### FormMeta Interface

217

218

Provides aggregate metadata about the form's validation state.

219

220

```typescript { .api }

221

interface FormMeta<TValues extends GenericObject> {

222

touched: boolean; // True if any field has been touched

223

dirty: boolean; // True if any field value differs from initial

224

valid: boolean; // True if all fields pass validation

225

pending: boolean; // True if any validation is in progress

226

initialValues?: Partial<TValues>; // Original form values

227

}

228

```

229

230

### FormState Interface

231

232

Complete form state structure for reset operations and state management.

233

234

```typescript { .api }

235

interface FormState<TValues> {

236

values: PartialDeep<TValues>; // Current field values

237

errors: Partial<Record<Path<TValues>, string | undefined>>; // Field error messages

238

touched: Partial<Record<Path<TValues>, boolean>>; // Field touched states

239

submitCount: number; // Number of submission attempts

240

}

241

```

242

243

### FormErrors Type

244

245

Type-safe error mapping for form fields.

246

247

```typescript { .api }

248

type FormErrors<TValues extends GenericObject> = Partial<Record<Path<TValues> | '', string | undefined>>;

249

type FormErrorBag<TValues extends GenericObject> = Partial<Record<Path<TValues> | '', string[]>>;

250

```

251

252

## Submission Handling

253

254

### SubmissionHandler Type

255

256

Type definition for form submission callbacks.

257

258

```typescript { .api }

259

type SubmissionHandler<TInput extends GenericObject = GenericObject, TOutput = TInput, TReturn = unknown> = (

260

values: TOutput,

261

ctx: SubmissionContext<TInput>

262

) => TReturn;

263

264

interface SubmissionContext<TInput extends GenericObject = GenericObject> extends FormActions<TInput> {

265

evt?: Event; // Original submit event

266

controlledValues: Partial<TInput>; // Current controlled form values

267

}

268

```

269

270

### InvalidSubmissionHandler Type

271

272

Type definition for handling invalid form submissions.

273

274

```typescript { .api }

275

type InvalidSubmissionHandler<TInput extends GenericObject = GenericObject, TOutput extends GenericObject = TInput> = (

276

ctx: InvalidSubmissionContext<TInput, TOutput>

277

) => void;

278

279

interface InvalidSubmissionContext<TInput extends GenericObject = GenericObject, TOutput extends GenericObject = TInput> {

280

values: TInput; // Current form values

281

evt?: Event; // Original submit event

282

errors: Partial<Record<Path<TInput>, string>>; // Current field errors

283

results: FormValidationResult<TInput, TOutput>['results']; // Detailed validation results

284

}

285

```

286

287

**Submission Examples:**

288

289

```typescript

290

import { useForm } from "vee-validate";

291

292

const { handleSubmit } = useForm();

293

294

// Basic submission

295

const onSubmit = handleSubmit((values) => {

296

console.log("Submitting:", values);

297

return fetch("/api/submit", {

298

method: "POST",

299

body: JSON.stringify(values)

300

});

301

});

302

303

// Submission with error handling

304

const onSubmitWithErrorHandling = handleSubmit(

305

async (values, { setFieldError, setErrors }) => {

306

try {

307

const response = await fetch("/api/submit", {

308

method: "POST",

309

body: JSON.stringify(values)

310

});

311

312

if (!response.ok) {

313

const errors = await response.json();

314

setErrors(errors);

315

return;

316

}

317

318

console.log("Success!");

319

} catch (error) {

320

setFieldError("", "Submission failed");

321

}

322

},

323

({ errors, results }) => {

324

console.log("Form is invalid:", errors);

325

console.log("Validation results:", results);

326

}

327

);

328

329

// Controlled form submission

330

const onControlledSubmit = handleSubmit.withControlled((values, ctx) => {

331

// Uses controlled values instead of current form values

332

console.log("Controlled values:", ctx.controlledValues);

333

return submitToAPI(ctx.controlledValues);

334

});

335

```

336

337

## Advanced Form Configuration

338

339

### Schema-based Forms

340

341

Using validation schemas for comprehensive form validation.

342

343

```typescript

344

import { useForm } from "vee-validate";

345

import * as yup from "yup";

346

347

// Yup schema

348

const yupSchema = yup.object({

349

user: yup.object({

350

name: yup.string().required(),

351

email: yup.string().email().required(),

352

profile: yup.object({

353

bio: yup.string().max(500),

354

age: yup.number().min(18)

355

})

356

})

357

});

358

359

const { handleSubmit, errors } = useForm({

360

validationSchema: yupSchema,

361

initialValues: {

362

user: {

363

name: "",

364

email: "",

365

profile: {

366

bio: "",

367

age: 0

368

}

369

}

370

}

371

});

372

373

// Raw schema with function validators

374

const rawSchema = {

375

"user.name": (value) => value ? true : "Name is required",

376

"user.email": [

377

(value) => value ? true : "Email is required",

378

(value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) || "Email is invalid"

379

],

380

"user.profile.bio": (value) => value.length <= 500 || "Bio too long"

381

};

382

383

const { handleSubmit: handleRawSubmit } = useForm({

384

validationSchema: rawSchema

385

});

386

```