Conditional Rules
Learn how to use NLG Form conditional rule helpers for required-if, prohibited-if, required-with, and required-without validation flows.
Conditional rule helpers provide shortcuts for common conditional validation patterns.
They are built on top of conditional.When, but make frequent validation cases easier to read and reuse.
Use conditional rule helpers when validation depends on other fields in the same request.
Common Use Cases
Conditional rules are commonly used for:
- company-only fields
- country-specific billing fields
- admin-only notes
- contact method validation
- address-dependent fields
- backup contact information
- onboarding flows
- profile completion
- dynamic form sections
TL;DR
| Helper | Description |
|---|---|
conditional.RequiredIfStr(field, cond) | Requires a string field when cond returns true |
conditional.RequiredIfStrWithCode(field, cond, code) | Same as RequiredIfStr with a custom error code |
conditional.ProhibitedIfStr(field, cond) | Forbids a non-blank string value when cond returns true |
conditional.ProhibitedIfStrWithCode(field, cond, code) | Same as ProhibitedIfStr with a custom error code |
conditional.RequiredWithAnyStr(field, others...) | Requires a string field when any other field is non-blank |
conditional.RequiredWithAnyStrWithCode(field, code, others...) | Same as RequiredWithAnyStr with a custom error code |
conditional.RequiredWithoutAnyStr(field, others...) | Requires a string field when any other field is blank |
conditional.RequiredWithoutAnyStrWithCode(field, code, others...) | Same as RequiredWithoutAnyStr with a custom error code |
Defining Conditional Fields
Conditional validation starts with regular typed string fields.
ConditionalRulesForm := struct {
AccountType form.StringField[ConditionalRulesRequest]
CompanyName form.StringField[ConditionalRulesRequest]
Country form.StringField[ConditionalRulesRequest]
VatNumber form.StringField[ConditionalRulesRequest]
Role form.StringField[ConditionalRulesRequest]
AdminNote form.StringField[ConditionalRulesRequest]
}{
AccountType: form.Str[ConditionalRulesRequest]("account_type", func(r *ConditionalRulesRequest) string {
return r.AccountType
}),
CompanyName: form.Str[ConditionalRulesRequest]("company_name", func(r *ConditionalRulesRequest) string {
return r.CompanyName
}),
Country: form.Str[ConditionalRulesRequest]("country", func(r *ConditionalRulesRequest) string {
return r.Country
}),
VatNumber: form.Str[ConditionalRulesRequest]("vat_number", func(r *ConditionalRulesRequest) string {
return r.VatNumber
}),
Role: form.Str[ConditionalRulesRequest]("role", func(r *ConditionalRulesRequest) string {
return r.Role
}),
AdminNote: form.Str[ConditionalRulesRequest]("admin_note", func(r *ConditionalRulesRequest) string {
return r.AdminNote
}),
}Applying Conditional Rules
Conditional helpers attach validation behavior to fields based on runtime values.
return form.Schema[ConditionalRulesRequest]{
conditional.RequiredIfStr(
ConditionalRulesForm.CompanyName,
func(r *ConditionalRulesRequest) bool {
return r.AccountType == "company"
},
),
conditional.RequiredIfStrWithCode(
ConditionalRulesForm.VatNumber,
func(r *ConditionalRulesRequest) bool {
return r.Country == "SK"
},
CodeVatNumberRequired,
),
conditional.ProhibitedIfStr(
ConditionalRulesForm.AdminNote,
func(r *ConditionalRulesRequest) bool {
return r.Role != "admin"
},
),
}Rule Examples
RequiredIfStr
Requires a string field when the condition returns true.
conditional.RequiredIfStr(
ConditionalRulesForm.CompanyName,
func(r *ConditionalRulesRequest) bool {
return r.AccountType == "company"
},
)This is useful when one field becomes mandatory based on another field.
RequiredIfStrWithCode
Requires a string field when the condition returns true and returns a custom validation code.
const CodeVatNumberRequired = form.Code("vat_number_required")
conditional.RequiredIfStrWithCode(
ConditionalRulesForm.VatNumber,
func(r *ConditionalRulesRequest) bool {
return r.Country == "SK"
},
CodeVatNumberRequired,
)This is useful for country-specific, account-specific, or workflow-specific validation.
ProhibitedIfStr
Forbids a non-blank string value when the condition returns true.
conditional.ProhibitedIfStr(
ConditionalRulesForm.AdminNote,
func(r *ConditionalRulesRequest) bool {
return r.Role != "admin"
},
)Validation behavior:
| Condition | Field value | Result |
|---|---|---|
false | any value | skipped |
true | "" | valid |
true | "secret note" | invalid |
ProhibitedIfStrWithCode
Forbids a non-blank string value when the condition returns true and returns a custom validation code.
const CodeInternalNoteBlocked = form.Code("internal_note_blocked")
conditional.ProhibitedIfStrWithCode(
ConditionalRulesForm.InternalNote,
func(r *ConditionalRulesRequest) bool {
return r.UserType == "external"
},
CodeInternalNoteBlocked,
)This is useful for protecting internal-only fields from public or external input.
RequiredWithAnyStr
Requires a field when any of the referenced fields is non-blank.
conditional.RequiredWithAnyStr(
ConditionalRulesForm.Email,
ConditionalRulesForm.Phone,
)This means:
if phone is filled, email is requiredTypical use cases:
- contact method pairs
- dependent address fields
- partially completed form sections
RequiredWithAnyStrWithCode
Requires a field when any referenced field is non-blank and returns a custom validation code.
const CodeContactRequired = form.Code("contact_required")
conditional.RequiredWithAnyStrWithCode(
ConditionalRulesForm.ContactName,
CodeContactRequired,
ConditionalRulesForm.Address,
ConditionalRulesForm.City,
)This means:
if address or city is filled, contact_name is requiredRequiredWithoutAnyStr
Requires a field when any referenced field is blank.
conditional.RequiredWithoutAnyStr(
ConditionalRulesForm.Phone,
ConditionalRulesForm.Email,
)This means:
if email is blank, phone is requiredTypical use cases:
- fallback contact fields
- at-least-one contact method
- alternative input paths
RequiredWithoutAnyStrWithCode
Requires a field when any referenced field is blank and returns a custom validation code.
const CodeBackupRequired = form.Code("backup_required")
conditional.RequiredWithoutAnyStrWithCode(
ConditionalRulesForm.BackupEmail,
CodeBackupRequired,
ConditionalRulesForm.BackupPhone,
)This means:
if backup_phone is blank, backup_email is requiredComplete Example
schema.go
package main
import (
"github.com/netlifeguru/form"
"github.com/netlifeguru/form/conditional"
)
const (
CodeVatNumberRequired = form.Code("vat_number_required")
CodeInternalNoteBlocked = form.Code("internal_note_blocked")
CodeContactRequired = form.Code("contact_required")
CodeBackupRequired = form.Code("backup_required")
)
type ConditionalRulesRequest struct {
AccountType string `json:"account_type"`
CompanyName string `json:"company_name"`
Country string `json:"country"`
VatNumber string `json:"vat_number"`
Role string `json:"role"`
AdminNote string `json:"admin_note"`
UserType string `json:"user_type"`
InternalNote string `json:"internal_note"`
Phone string `json:"phone"`
Email string `json:"email"`
Address string `json:"address"`
City string `json:"city"`
ContactName string `json:"contact_name"`
BackupEmail string `json:"backup_email"`
BackupPhone string `json:"backup_phone"`
}
func ConditionalRulesSchema() form.Schema[ConditionalRulesRequest] {
ConditionalRulesForm := struct {
AccountType form.StringField[ConditionalRulesRequest]
CompanyName form.StringField[ConditionalRulesRequest]
Country form.StringField[ConditionalRulesRequest]
VatNumber form.StringField[ConditionalRulesRequest]
Role form.StringField[ConditionalRulesRequest]
AdminNote form.StringField[ConditionalRulesRequest]
UserType form.StringField[ConditionalRulesRequest]
InternalNote form.StringField[ConditionalRulesRequest]
Phone form.StringField[ConditionalRulesRequest]
Email form.StringField[ConditionalRulesRequest]
Address form.StringField[ConditionalRulesRequest]
City form.StringField[ConditionalRulesRequest]
ContactName form.StringField[ConditionalRulesRequest]
BackupEmail form.StringField[ConditionalRulesRequest]
BackupPhone form.StringField[ConditionalRulesRequest]
}{
AccountType: form.Str[ConditionalRulesRequest]("account_type", func(r *ConditionalRulesRequest) string {
return r.AccountType
}),
CompanyName: form.Str[ConditionalRulesRequest]("company_name", func(r *ConditionalRulesRequest) string {
return r.CompanyName
}),
Country: form.Str[ConditionalRulesRequest]("country", func(r *ConditionalRulesRequest) string {
return r.Country
}),
VatNumber: form.Str[ConditionalRulesRequest]("vat_number", func(r *ConditionalRulesRequest) string {
return r.VatNumber
}),
Role: form.Str[ConditionalRulesRequest]("role", func(r *ConditionalRulesRequest) string {
return r.Role
}),
AdminNote: form.Str[ConditionalRulesRequest]("admin_note", func(r *ConditionalRulesRequest) string {
return r.AdminNote
}),
UserType: form.Str[ConditionalRulesRequest]("user_type", func(r *ConditionalRulesRequest) string {
return r.UserType
}),
InternalNote: form.Str[ConditionalRulesRequest]("internal_note", func(r *ConditionalRulesRequest) string {
return r.InternalNote
}),
Phone: form.Str[ConditionalRulesRequest]("phone", func(r *ConditionalRulesRequest) string {
return r.Phone
}),
Email: form.Str[ConditionalRulesRequest]("email", func(r *ConditionalRulesRequest) string {
return r.Email
}),
Address: form.Str[ConditionalRulesRequest]("address", func(r *ConditionalRulesRequest) string {
return r.Address
}),
City: form.Str[ConditionalRulesRequest]("city", func(r *ConditionalRulesRequest) string {
return r.City
}),
ContactName: form.Str[ConditionalRulesRequest]("contact_name", func(r *ConditionalRulesRequest) string {
return r.ContactName
}),
BackupEmail: form.Str[ConditionalRulesRequest]("backup_email", func(r *ConditionalRulesRequest) string {
return r.BackupEmail
}),
BackupPhone: form.Str[ConditionalRulesRequest]("backup_phone", func(r *ConditionalRulesRequest) string {
return r.BackupPhone
}),
}
return form.Schema[ConditionalRulesRequest]{
conditional.RequiredIfStr(
ConditionalRulesForm.CompanyName,
func(r *ConditionalRulesRequest) bool {
return r.AccountType == "company"
},
),
conditional.RequiredIfStrWithCode(
ConditionalRulesForm.VatNumber,
func(r *ConditionalRulesRequest) bool {
return r.Country == "SK"
},
CodeVatNumberRequired,
),
conditional.ProhibitedIfStr(
ConditionalRulesForm.AdminNote,
func(r *ConditionalRulesRequest) bool {
return r.Role != "admin"
},
),
conditional.ProhibitedIfStrWithCode(
ConditionalRulesForm.InternalNote,
func(r *ConditionalRulesRequest) bool {
return r.UserType == "external"
},
CodeInternalNoteBlocked,
),
conditional.RequiredWithAnyStr(
ConditionalRulesForm.Email,
ConditionalRulesForm.Phone,
),
conditional.RequiredWithAnyStrWithCode(
ConditionalRulesForm.ContactName,
CodeContactRequired,
ConditionalRulesForm.Address,
ConditionalRulesForm.City,
),
conditional.RequiredWithoutAnyStr(
ConditionalRulesForm.Phone,
ConditionalRulesForm.Email,
),
conditional.RequiredWithoutAnyStrWithCode(
ConditionalRulesForm.BackupEmail,
CodeBackupRequired,
ConditionalRulesForm.BackupPhone,
),
}
}main.go
package main
import (
"encoding/json"
"fmt"
"log/slog"
"net/http"
"os"
"github.com/netlifeguru/form"
"github.com/netlifeguru/form/httpform"
"github.com/netlifeguru/router"
)
func main() {
r := router.New()
r.HandleFunc("/conditional-rules", "POST", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
var in ConditionalRulesRequest
if !httpform.BindAndValidate(w, req, &in, ConditionalRulesSchema(), 1<<20) {
fmt.Println("conditional rules validation failed")
return
}
fmt.Println("conditional rules validation passed:", in)
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]any{
"message": "conditional rules validation passed",
"data": in,
})
})
validPayload := map[string]any{
"account_type": "company",
"company_name": "Acme s.r.o.",
"country": "SK",
"vat_number": "SK1234567890",
"role": "user",
"admin_note": "",
"user_type": "external",
"internal_note": "",
"phone": "+421900123456",
"email": "john@example.com",
"address": "Main Street 1",
"city": "",
"contact_name": "John Doe",
"backup_email": "backup@example.com",
"backup_phone": "",
}
invalidPayload := map[string]any{
"account_type": "company",
"company_name": "",
"country": "SK",
"vat_number": "",
"role": "user",
"admin_note": "internal only",
"user_type": "external",
"internal_note": "secret note",
"phone": "+421900123456",
"email": "",
"address": "Main Street 1",
"city": "",
"contact_name": "",
"backup_email": "",
"backup_phone": "",
}
fmt.Println("\n--- Valid request ---")
form.SendTestPost(":8080/conditional-rules", validPayload)
fmt.Println("\n--- Invalid request ---")
form.SendTestPost(":8080/conditional-rules", invalidPayload)
if err := r.ListenAndServe(8080); err != nil {
slog.Error("failed to start server", "error", err)
os.Exit(1)
}
}Notes
- Conditional rule helpers are shortcuts for common
Whenpatterns. - Conditions receive the full request structure.
- String conditional helpers use blank-string behavior based on trimmed string values.
- Use
RequiredIfStrwhen a field becomes required in a specific state. - Use
ProhibitedIfStrwhen a field must stay empty in a specific state. - Use
RequiredWithAnyStrwhen one field depends on another field being filled. - Use
RequiredWithoutAnyStrwhen one field is required as a fallback. - Use
Whendirectly for advanced rule composition or multiple nested rules.