Skip to content
duyetvo edited this page Jan 8, 2026 · 4 revisions

React Validator Form

A Lightweight, Extensible Validation Core for React Applications

1. Introduction

React Validator Form is a lightweight, extensible validation framework designed for React applications that require full control over validation logic without the constraints of opinionated form libraries.

Unlike full-featured solutions such as Formik or React Hook Form, this project focuses on validation as a first-class concern, allowing teams to:

  • Design custom validation rules
  • Maintain a clear separation between UI and validation logic
  • Extend validation behavior incrementally as application complexity grows
  • Learn and build their own form validation architecture

This project can be used as:

  • A foundation for custom form systems
  • A reference implementation for rule-based validation
  • A starter template for enterprise or internal tools

2. Design Principles

The architecture is guided by the following principles:

2.1 Separation of Concerns

  • Validation logic is isolated from UI components
  • Rules are reusable, composable, and testable

2.2 Extensibility

  • Validation rules follow an object-oriented design
  • New rules can be added without modifying existing logic

2.3 Predictability

  • Each field produces a deterministic validation result
  • Validation output structure is consistent across rules

2.4 Minimalism

  • No external validation dependencies
  • No forced schema or hook usage
  • Easy to reason about and debug

3. High-Level Architecture

image

4. Core Concepts

4.1 BaseRule (Validation Contract) All validation rules inherit from a shared abstract base:

`export abstract class BaseRule { abstract test(params: RuleParam): boolean; abstract res(params: RuleParam): RuleResponse;

message(orgMsg: string, fieldName: string, arg: string): string { return orgMsg .replace("{#fieldName}", fieldName) .replace("{#arg}", arg); } }`

Responsibilities:

test() → Determine if the rule passes res() → Return a standardized validation response message() → Normalize error message formatting

This enforces consistency across all validation rules.

4.2 Rule Keys & Mapping

Rules are referenced by semantic keys: export enum RuleKey { required = "required", phone = "phone", }

Mapping keys to rule instances enables dynamic rule execution: const RulesMapping = [ { ruleName: RuleKey.required, inst: new RequiredRule() }, { ruleName: RuleKey.phone, inst: new PhoneRule() }, ];

Benefits:

  • Centralized rule registration
  • Easy rule replacement or extension
  • Clear contract between UI and validation engine

4.3 Validator Engine

The Validator acts as the execution engine:

Validator.run( rules: Rules, fieldName: string, value: string ): FieldResult

Returns: { isValid: boolean; res?: RuleResponse[]; }

  • Executes all configured rules for a field
  • Aggregates rule failures
  • Produces a single validation result per field

4.4 Field Components

Field components (e.g. Textbox) are responsible for:

  • Tracking field value
  • Triggering validation on events (change, blur, submit)
  • Rendering validation feedback

Typical flow: const result = validator.run(rules, name, value); setErrors(result.res ?? []);

UI components remain stateless with respect to validation logic, improving reusability.


5. Getting Started

5.1 Installation git clone https://github.com/duyetvv/react-validator-form.git cd react-validator-form npm install

5.2 Development npm start # or npm run dev

5.3 Build npm run build

6. Usage Example

<Textbox name="phone" label="Phone Number" rules={{ required: true, phone: true }} store={store} />

Validation lifecycle:

  1. User updates input
  2. Field triggers validator
  3. Rules are executed
  4. Errors are rendered (if any)
  5. Form validity is recalculated

7. Extending the System

7.1 Creating a Custom Rule

`class MinLengthRule extends BaseRule { test({ val, arg }) { return val.length >= Number(arg); }

res({ name, arg }) { return { name, message: Minimum length is ${arg}, }; } }`

7.2 Register the Rule RulesMapping.push({ ruleName: RuleKey.minLength, inst: new MinLengthRule(), });

8. State Management Strategy

This project intentionally avoids enforcing a state library.

You may integrate:

React Context Redux / Zustand Custom store pattern (as shown)

Recommendation: Keep validation state centralized at form level, while field components remain isolated.