Skip to main content

Required Rules

Conditional required validation rules that make fields required based on other field values or presence.


All Methods


Based on Field Presence

requiredWith()

Value is required if another field exists.

Signature:

requiredWith(field: string, errorMessage?: string): this

Example:

v.string().requiredWith("email")

// Input: { email: "user@example.com", name: "John" }
// Output: "John" ✅

// Input: { email: "user@example.com", name: undefined }
// Output: Error: "The :input is required" ❌

// Input: { name: "John" }
// Output: "John" ✅ (email not present, so name not required)

Common Use:

// Contact form - name required if email provided
v.object({
email: v.string().optional().email(),
name: v.string().requiredWith("email")
});

requiredWithout()

Value is required if another field is missing.

Signature:

requiredWithout(field: string, errorMessage?: string): this

Example:

v.string().requiredWithout("email")

// Input: { email: "user@example.com", phone: undefined }
// Output: undefined ✅ (email present, so phone not required)

// Input: { phone: "123-456-7890" }
// Output: "123-456-7890" ✅ (email not present, so phone required)

// Input: { email: undefined, phone: undefined }
// Output: Error: "The :input is required" ❌

Common Use:

// Contact form - phone required if no email
v.object({
email: v.string().optional().email(),
phone: v.string().requiredWithout("email").phone()
});

requiredWithSibling()

Value is required if another sibling field exists (for nested objects).

Signature:

requiredWithSibling(field: string, errorMessage?: string): this

Example:

// Nested object validation
v.object({
user: v.object({
email: v.string().optional().email(),
name: v.string().requiredWithSibling("email")
})
});

requiredWithoutSibling()

Value is required if another sibling field is missing (for nested objects).

Signature:

requiredWithoutSibling(field: string, errorMessage?: string): this

Example:

// Nested object validation
v.object({
user: v.object({
email: v.string().optional().email(),
phone: v.string().requiredWithoutSibling("email")
})
});

Based on Field Value

requiredIf()

Value is required if another field equals a specific value.

Signature:

requiredIf(field: string, value: any, errorMessage?: string): this

Example:

v.string().requiredIf("type", "admin")

// Input: { type: "admin", role: "super-admin" }
// Output: "super-admin" ✅

// Input: { type: "admin", role: undefined }
// Output: Error: "The :input is required" ❌

// Input: { type: "user", role: undefined }
// Output: undefined ✅ (type not "admin", so role not required)

Common Use:

// User registration - role required for admin
v.object({
type: v.string().required().oneOf(["admin", "user"]),
role: v.string().requiredIf("type", "admin")
});

requiredUnless()

Value is required unless another field equals a specific value.

Signature:

requiredUnless(field: string, value: any, errorMessage?: string): this

Example:

v.string().requiredUnless("type", "guest")

// Input: { type: "user", name: "John" }
// Output: "John" ✅

// Input: { type: "user", name: undefined }
// Output: Error: "The :input is required" ❌

// Input: { type: "guest", name: undefined }
// Output: undefined ✅ (type is "guest", so name not required)

Common Use:

// User registration - name required unless guest
v.object({
type: v.string().required().oneOf(["admin", "user", "guest"]),
name: v.string().requiredUnless("type", "guest")
});

requiredIfSibling()

Value is required if another sibling field equals a specific value (for nested objects).

Signature:

requiredIfSibling(field: string, value: any, errorMessage?: string): this

Example:

// Nested object validation
v.object({
user: v.object({
type: v.string().required().oneOf(["admin", "user"]),
role: v.string().requiredIfSibling("type", "admin")
})
});

requiredUnlessSibling()

Value is required unless another sibling field equals a specific value (for nested objects).

Signature:

requiredUnlessSibling(field: string, value: any, errorMessage?: string): this

Example:

// Nested object validation
v.object({
user: v.object({
type: v.string().required().oneOf(["admin", "user", "guest"]),
name: v.string().requiredUnlessSibling("type", "guest")
})
});

Based on Field Empty State

requiredIfEmpty()

Value is required if another field is empty.

Signature:

requiredIfEmpty(field: string, errorMessage?: string): this

Example:

v.string().requiredIfEmpty("email")

// Input: { email: "", phone: "123-456-7890" }
// Output: "123-456-7890" ✅

// Input: { email: "", phone: undefined }
// Output: Error: "The :input is required" ❌

// Input: { email: "user@example.com", phone: undefined }
// Output: undefined ✅ (email not empty, so phone not required)

Common Use:

// Contact form - phone required if email empty
v.object({
email: v.string().optional().email(),
phone: v.string().requiredIfEmpty("email").phone()
});

requiredIfNotEmpty()

Value is required if another field is not empty.

Signature:

requiredIfNotEmpty(field: string, errorMessage?: string): this

Example:

v.string().requiredIfNotEmpty("email")

// Input: { email: "user@example.com", name: "John" }
// Output: "John" ✅

// Input: { email: "user@example.com", name: undefined }
// Output: Error: "The :input is required" ❌

// Input: { email: "", name: undefined }
// Output: undefined ✅ (email empty, so name not required)

Common Use:

// Profile form - name required if email provided
v.object({
email: v.string().optional().email(),
name: v.string().requiredIfNotEmpty("email")
});

requiredIfEmptySibling()

Value is required if another sibling field is empty (for nested objects).

Signature:

requiredIfEmptySibling(field: string, errorMessage?: string): this

Example:

// Nested object validation
v.object({
user: v.object({
email: v.string().optional().email(),
phone: v.string().requiredIfEmptySibling("email")
})
});

requiredIfNotEmptySibling()

Value is required if another sibling field is not empty (for nested objects).

Signature:

requiredIfNotEmptySibling(field: string, errorMessage?: string): this

Example:

// Nested object validation
v.object({
user: v.object({
email: v.string().optional().email(),
name: v.string().requiredIfNotEmptySibling("email")
})
});

Based on Field Value Arrays

requiredIfIn()

Value is required if another field's value is in the given array.

Signature:

requiredIfIn(field: string, values: any[], errorMessage?: string): this

Example:

v.string().requiredIfIn("type", ["admin", "moderator"])

// Input: { type: "admin", role: "super-admin" }
// Output: "super-admin" ✅

// Input: { type: "admin", role: undefined }
// Output: Error: "The :input is required" ❌

// Input: { type: "user", role: undefined }
// Output: undefined ✅ (type not in ["admin", "moderator"])

Common Use:

// User roles - role required for admin/moderator
v.object({
type: v.string().required().oneOf(["admin", "moderator", "user"]),
role: v.string().requiredIfIn("type", ["admin", "moderator"])
});

requiredIfNotIn()

Value is required if another field's value is NOT in the given array.

Signature:

requiredIfNotIn(field: string, values: any[], errorMessage?: string): this

Example:

v.string().requiredIfNotIn("type", ["guest", "anonymous"])

// Input: { type: "user", name: "John" }
// Output: "John" ✅

// Input: { type: "user", name: undefined }
// Output: Error: "The :input is required" ❌

// Input: { type: "guest", name: undefined }
// Output: undefined ✅ (type in ["guest", "anonymous"])

Common Use:

// User registration - name required for registered users
v.object({
type: v.string().required().oneOf(["admin", "user", "guest", "anonymous"]),
name: v.string().requiredIfNotIn("type", ["guest", "anonymous"])
});

requiredIfInSibling()

Value is required if another sibling field's value is in the given array (for nested objects).

Signature:

requiredIfInSibling(field: string, values: any[], errorMessage?: string): this

Example:

// Nested object validation
v.object({
user: v.object({
type: v.string().required().oneOf(["admin", "moderator", "user"]),
role: v.string().requiredIfInSibling("type", ["admin", "moderator"])
})
});

requiredIfNotInSibling()

Value is required if another sibling field's value is NOT in the given array (for nested objects).

Signature:

requiredIfNotInSibling(field: string, values: any[], errorMessage?: string): this

Example:

// Nested object validation
v.object({
user: v.object({
type: v.string().required().oneOf(["admin", "user", "guest", "anonymous"]),
name: v.string().requiredIfNotInSibling("type", ["guest", "anonymous"])
})
});

Multiple Field Rules

requiredWithAll()

Value is required if all specified fields exist.

Signature:

requiredWithAll(fields: string[], errorMessage?: string): this

Example:

v.string().requiredWithAll(["email", "phone"])

// Input: { email: "user@example.com", phone: "123-456-7890", name: "John" }
// Output: "John" ✅

// Input: { email: "user@example.com", phone: "123-456-7890", name: undefined }
// Output: Error: "The :input is required" ❌

// Input: { email: "user@example.com", name: "John" }
// Output: "John" ✅ (phone not present, so name not required)

Common Use:

// Complete profile - name required if both email and phone provided
v.object({
email: v.string().optional().email(),
phone: v.string().optional().phone(),
name: v.string().requiredWithAll(["email", "phone"])
});

requiredWithAny()

Value is required if any of the specified fields exists.

Signature:

requiredWithAny(fields: string[], errorMessage?: string): this

Example:

v.string().requiredWithAny(["email", "phone"])

// Input: { email: "user@example.com", name: "John" }
// Output: "John" ✅

// Input: { email: "user@example.com", name: undefined }
// Output: Error: "The :input is required" ❌

// Input: { name: "John" }
// Output: "John" ✅ (neither email nor phone present)

Common Use:

// Contact form - name required if any contact method provided
v.object({
email: v.string().optional().email(),
phone: v.string().optional().phone(),
name: v.string().requiredWithAny(["email", "phone"])
});

requiredWithAllSiblings()

Value is required if all specified sibling fields exist (for nested objects).

Signature:

requiredWithAllSiblings(fields: string[], errorMessage?: string): this

Example:

// Nested object validation
v.object({
user: v.object({
email: v.string().optional().email(),
phone: v.string().optional().phone(),
name: v.string().requiredWithAllSiblings(["email", "phone"])
})
});

requiredWithoutAll()

Value is required if all specified fields are missing.

Signature:

requiredWithoutAll(fields: string[], errorMessage?: string): this

Example:

v.string().requiredWithoutAll(["email", "phone"])

// Input: { name: "John" }
// Output: "John" ✅ (both email and phone missing)

// Input: { email: "user@example.com", name: undefined }
// Output: undefined ✅ (email present, so name not required)

// Input: { name: undefined }
// Output: Error: "The :input is required" ❌

requiredWithoutAllSiblings()

Value is required if all specified sibling fields are missing (for nested objects).

Signature:

requiredWithoutAllSiblings(fields: string[], errorMessage?: string): this

Example:

// Nested object validation
v.object({
user: v.object({
email: v.string().optional().email(),
phone: v.string().optional().phone(),
name: v.string().requiredWithoutAllSiblings(["email", "phone"])
})
});

requiredWithAnySiblings()

Value is required if any of the specified sibling fields exists (for nested objects).

Signature:

requiredWithAnySiblings(fields: string[], errorMessage?: string): this

Example:

// Nested object validation
v.object({
user: v.object({
email: v.string().optional().email(),
phone: v.string().optional().phone(),
name: v.string().requiredWithAnySiblings(["email", "phone"])
})
});

requiredWithoutAny()

Value is required if any of the specified fields is missing.

Signature:

requiredWithoutAny(fields: string[], errorMessage?: string): this

Example:

v.string().requiredWithoutAny(["email", "phone"])

// Input: { email: "user@example.com", name: "John" }
// Output: "John" ✅ (phone missing)

// Input: { email: "user@example.com", phone: "123-456-7890", name: undefined }
// Output: undefined ✅ (both email and phone present)

// Input: { name: undefined }
// Output: Error: "The :input is required" ❌

requiredWithoutAnySiblings()

Value is required if any of the specified sibling fields is missing (for nested objects).

Signature:

requiredWithoutAnySiblings(fields: string[], errorMessage?: string): this

Example:

// Nested object validation
v.object({
user: v.object({
email: v.string().optional().email(),
phone: v.string().optional().phone(),
name: v.string().requiredWithoutAnySiblings(["email", "phone"])
})
});

Chaining Examples

// Complex conditional validation
v.string()
.requiredIf("type", "admin")
.requiredIfNotEmpty("email")
.requiredWithAny(["phone", "address"])
.min(3)
.max(50)

Real-World Examples

User Registration Form

const registrationSchema = v.object({
type: v.string().required().oneOf(["admin", "user", "guest"]),
email: v.string().optional().email(),
phone: v.string().optional().phone(),
name: v.string().requiredUnless("type", "guest"),
role: v.string().requiredIf("type", "admin"),
address: v.string().requiredWithAll(["email", "phone"])
});

Contact Form

const contactSchema = v.object({
email: v.string().optional().email(),
phone: v.string().optional().phone(),
name: v.string().requiredWithAny(["email", "phone"]),
message: v.string().required().min(10)
});

See Also