Form Fields & Validation

Production-ready React form components with TypeScript: image upload with preview & download, date pickers (single/range/time), and comprehensive form validation using Yup and React Hook Form.

Interactive Form Demo

Off

Conditional Submit Button Demo

Type "confirm" in the field below to enable the Delete button. This is useful for destructive actions that require user confirmation.

How it works:

  • The Delete button is initially disabled
  • When you type "confirm" (exactly), the button becomes enabled
  • If you change the text to anything else, it disables again
  • This prevents accidental destructive actions

Component Features

  • Text Input Fields: Standard text input with validation, error handling, and TypeScript support
  • Email Validation: Built-in email format validation with custom error messages
  • Image Upload Component: File upload with instant preview, base64 conversion, image download, and modal preview
  • Single Date Picker: Select individual dates with custom formatting options
  • Date & Time Picker: Combined date and time selection with 12/24 hour formats
  • Date Range Picker: Select start and end dates for date ranges (vacations, bookings, etc.)
  • Toggle Switch: Boolean checkbox with custom labels and validation
  • Form Validation: Powered by Yup with custom validation rules and error messages
  • React Hook Form: Efficient form state management with minimal re-renders
  • Automatic Type Detection: Intelligent validation based on field types - no manual schemas needed

Code Examples & Implementation

Date Picker Field Configuration

// Single Date Picker
{
  name: 'birthDate',
  label: 'Birth Date',
  type: 'date',
  dateMode: 'single',
  dateFormat: 'Y-m-d',
  required: true,
  validation: Yup.date().required('Birth date is required'),
}

Date Range Picker Configuration

// Date Range Picker
{
  name: 'vacationDates',
  label: 'Vacation Period',
  type: 'date',
  dateMode: 'range',
  dateFormat: 'M j, Y',
  // Auto-validation: Yup.array().of(Yup.date()).nullable()
}

Date & Time Picker Configuration

// Date & Time Picker
{
  name: 'eventDate',
  label: 'Event Date & Time',
  type: 'datepicker',
  dateMode: 'single',
  dateFormat: 'Y-m-d H:i',
  enableTime: true,
  time24hr: true,
  // Auto-validation: Yup.date().nullable()
}

Image Upload Field Configuration

// Image Upload with Preview & Download
{
  name: 'profileImage',
  label: 'Profile Image',
  type: 'file',
  hint: 'Click to upload image (PNG, JPG)',
  // Auto-validation: Yup.string().nullable()
  // Returns: base64 encoded string
}

Complete Form Setup - Step by Step

Step 1: Define Your Form Data Type

import type { Field } from '@/utils/field';
import * as Yup from 'yup';

// Define the shape of your form data
type DemoFormData = {
  name: string;
  email: string;
  profileImage: string;
  birthDate: Date | string;
  eventDate: Date | string;
  vacationDates: Date[];
  description: string;
  agree: boolean;
};

Step 2: Define Form Fields Configuration

const fields: { [k in keyof DemoFormData | string]: Field<DemoFormData> } = {
  name: {
    name: 'name',
    label: 'Full Name',
    type: 'text',
    placeholder: 'Enter your full name',
    required: true,
    validation: Yup.string().required('Name is required'),
  },
  email: {
    name: 'email',
    label: 'Email Address',
    type: 'email',
    placeholder: 'your.email@example.com',
    required: true,
    validation: Yup.string()
      .email('Invalid email address')
      .required('Email is required'),
  },
  profileImage: {
    name: 'profileImage',
    label: 'Profile Image',
    type: 'file',
    hint: 'Click to upload your profile picture',
    required: false,
  },
  birthDate: {
    name: 'birthDate',
    label: 'Birth Date',
    type: 'date',
    dateMode: 'single',
    dateFormat: 'Y-m-d',
    required: true,
    validation: Yup.date().required('Birth date is required'),
  },
  vacationDates: {
    name: 'vacationDates',
    label: 'Vacation Period',
    type: 'date',
    dateMode: 'range',
    dateFormat: 'M j, Y',
    hint: 'Select a date range for your vacation',
  },
  description: {
    name: 'description',
    label: 'Description',
    type: 'text',
    placeholder: 'Tell us about yourself...',
    required: false,
  },
  agree: {
    name: 'agree',
    label: 'I agree to the terms and conditions',
    type: 'toggle',
    required: true,
    validation: Yup.boolean()
      .oneOf([true], 'You must accept the terms')
      .required(),
  },
};

Step 3: Create Submit Handler

const handleSubmit = async (data: DemoFormData) => {
  console.log('Form submitted with data:', data);
  
  // Process the data
  // - data.name: string
  // - data.email: string
  // - data.profileImage: base64 string
  // - data.birthDate: Date
  // - data.vacationDates: Date[]
  
  // Return true to indicate success (clears form)
  // Return false to keep form data
  return true;
};

Step 4: Render the Form Component

import Form from '@/partials/grid/form';

function MyFormPage() {
  return (
    <Form<DemoFormData>
      fields={fields}
      onSubmit={handleSubmit}
      onCancel={(e, data) => {
        console.log('Cancelled with data:', data);
      }}
      saveLabel="Submit Form"
      cancelLabel="Reset"
    />
  );
}

Step 5: Complete Working Example

import React, { useState } from 'react';
import * as Yup from 'yup';
import Form from '@/partials/grid/form';
import type { Field } from '@/utils/field';

type UserForm = {
  name: string;
  email: string;
  birthDate: Date;
};

export default function UserFormPage() {
  const [submittedData, setSubmittedData] = useState<UserForm | null>(null);

  const fields: { [k in keyof UserForm]: Field<UserForm> } = {
    name: {
      name: 'name',
      label: 'Name',
      type: 'text',
      required: true,
      validation: Yup.string().required('Required'),
    },
    email: {
      name: 'email',
      label: 'Email',
      type: 'email',
      required: true,
      validation: Yup.string().email().required(),
    },
    birthDate: {
      name: 'birthDate',
      label: 'Birth Date',
      type: 'date',
      dateMode: 'single',
      required: true,
    },
  };

  const handleSubmit = async (data: UserForm) => {
    setSubmittedData(data);
    console.log('Submitted:', data);
    return true; // Clear form after submit
  };

  return (
    <div className="max-w-2xl mx-auto p-6">
      <h1 className="text-2xl font-bold mb-6">User Form</h1>
      
      <Form<UserForm>
        fields={fields}
        onSubmit={handleSubmit}
        saveLabel="Submit"
      />

      {submittedData && (
        <div className="mt-6 p-4 bg-green-50 rounded">
          <h2 className="font-semibold mb-2">Submitted Data:</h2>
          <pre>{JSON.stringify(submittedData, null, 2)}</pre>
        </div>
      )}
    </div>
  );
}

All Available Field Types

// Text Fields
type: 'text'       // Standard text input
type: 'email'      // Email with validation
type: 'password'   // Password field
type: 'textarea'   // Multi-line text
type: 'number'     // Number input
type: 'tel'        // Phone number

// Date/Time Fields  
type: 'date'       // Date picker (single, range, multiple)
type: 'datepicker' // Date picker with time support

// Selection Fields
type: 'select'     // Dropdown select
type: 'multiselect' // Multi-select dropdown
type: 'radio'      // Radio buttons
type: 'checkbox'   // Checkbox group

// Toggle/Boolean
type: 'toggle'     // Toggle switch

// File Upload
type: 'file'       // File upload (returns base64)

// Display Only
type: 'label'      // Display label only
type: 'empty'      // Empty space/divider

// Advanced
type: 'range'      // Number range slider
type: 'color'      // Color picker

Common Field Properties

{
  name: 'fieldName',              // Required: Field identifier
  label: 'Field Label',           // Display label
  type: 'text',                   // Required: Field type
  placeholder: 'Enter value...',  // Placeholder text
  hint: 'Helper text',            // Help text below field
  required: true,                 // Mark as required
  disabled: false,                // Disable field
  default: 'default value',       // Default value
  validation: Yup.string(),       // Yup validation schema
  
  // Conditional display
  showInCreateMode: true,         // Show in create mode
  showInEditMode: true,           // Show in edit mode
  
  // Date-specific (for type: 'date' | 'datepicker')
  dateMode: 'single',             // 'single' | 'range' | 'multiple'
  dateFormat: 'Y-m-d',            // Date format string
  enableTime: true,               // Enable time picker
  time24hr: true,                 // 24-hour format
  
  // Select-specific (for type: 'select')
  options: [                      // Dropdown options
    { label: 'Option 1', value: 'val1' },
    { label: 'Option 2', value: 'val2' },
  ],
}

Advanced: Conditional Submit Button (submitWatchField)

Control submit button visibility or enabled state based on field values. Perfect for confirmation fields, terms acceptance, or delete confirmations.

// Example: Require user to type "confirm" to enable delete button
<Form<UserForm>
  fields={fields}
  onSubmit={handleDelete}
  saveLabel="Delete"
  submitWatchField={{
    name: 'confirmText',        // Field to watch
    value: 'confirm',           // Value to match
    action: 'enable',           // 'show' | 'hide' | 'enable' | 'disable'
    operator: 'eq',             // 'eq' (equals) | 'ne' (not equals)
  }}
/>

// submitWatchField Options:
{
  name: string;              // Field name to watch
  value?: any;               // Single value to match
  values?: any[];            // Multiple values to match (OR condition)
  is_regex?: boolean;        // Treat value as regex pattern
  operator?: 'eq' | 'ne';    // 'eq' = equals (default), 'ne' = not equals
  action?: string;           // 'show' | 'hide' | 'enable' | 'disable'
}

// Actions:
// - 'show': Show button when condition is true (hidden when false)
// - 'hide': Hide button when condition is true (shown when false) 
// - 'enable': Enable button when condition is true (disabled when false)
// - 'disable': Disable button when condition is true (enabled when false)

Why Use These Components?

  • Type-Safe: Full TypeScript support with strong typing
  • Production Ready: Battle-tested in real-world applications
  • Accessible: WCAG compliant with ARIA labels and keyboard navigation
  • Customizable: Flexible styling with Tailwind CSS
  • Automatic Validation: Smart validation based on field types
  • Performance Optimized: Minimal re-renders with React Hook Form
  • Dark Mode: Built-in dark mode support
  • Responsive: Mobile-first design that works on all devices
  • Zero Config: Works out of the box with sensible defaults
  • Developer Friendly: Clear API with comprehensive examples

Perfect For

Registration Forms

User signup, account creation, profile setup with image upload

Booking Systems

Hotels, appointments, event reservations with date/time selection

E-commerce Checkouts

Shipping forms, payment details, order customization

Admin Dashboards

Content management, user administration, settings panels