Gecko UIGecko UI

RHFDateInput

Date input component integrated with React Hook Form

RHFDateInput

A date input component integrated with React Hook Form that automatically displays error states with a red border when validation fails. Accepts and displays dates in MM/DD/YYYY format with automatic formatting as the user types.

Installation

import { RHFDateInput } from '@geckoui/geckoui';

Basic Usage

MM/DD/YYYY
//
import { useForm, FormProvider } from 'react-hook-form';
import { RHFDateInput } from '@geckoui/geckoui';

function Example() {
  const methods = useForm({
    defaultValues: {
      basicBirthday: ''
    }
  });

  return (
    <FormProvider {...methods}>
      <RHFDateInput name="basicBirthday" placeholder="MM/DD/YYYY" format="MM/DD/YYYY" />
    </FormProvider>
  );
}

Props API

Extends all props from DateInput component plus:

PropTypeDefaultDescription
namestring-Field name (required)
controlControlAuto-injectedOptional: Pass explicitly for nested forms or custom form context
rulesRegisterOptions-Inline validation rules
classNamestring-Additional CSS class name for the input container
disabledboolean-Whether the input is disabled
prefixReactNode | Function-Element before input
suffixReactNode | Function-Element after input
onChange(value: string) => void-Change callback
onBlur(value: string) => void-Blur callback

Examples

With Validation (Zod)

MM/DD/YYYY
//
import { useForm, FormProvider } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { RHFDateInput, RHFInputGroup } from '@geckoui/geckoui';

const schema = z.object({
  validationStartDate: z.string()
    .min(1, 'Start date is required')
});

function Example() {
  const methods = useForm({
    resolver: zodResolver(schema),
    mode: 'onBlur',
    defaultValues: { validationStartDate: '' }
  });

  return (
    <FormProvider {...methods}>
      <RHFInputGroup label="Start Date" required>
        <RHFDateInput name="validationStartDate" placeholder="MM/DD/YYYY" format="MM/DD/YYYY" />
      </RHFInputGroup>
    </FormProvider>
  );
}

With Prefix and Suffix

📅
MM/DD/YYYY
//
Event Date
<RHFDateInput
  name="prefixEventDate"
  placeholder="MM/DD/YYYY"
  format="MM/DD/YYYY"
  prefix={<span className="text-gray-400">📅</span>}
  suffix={<span className="text-gray-400 text-xs">Event Date</span>}
  hideCalendarIcon
/>

With Date Range Validation

MM/DD/YYYY
//
const today = new Date();
const minDate = new Date(today);
minDate.setFullYear(today.getFullYear() - 100);
const maxDate = new Date(today);

const formatDate = (date: Date) => {
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const year = date.getFullYear();
  return `${month}/${day}/${year}`;
};

const schema = z.object({
  rangeValidationBirthDate: z.string()
    .min(1, 'Birth date is required')
    .refine((dateStr) => {
      const [month, day, year] = dateStr.split('/').map(Number);
      const date = new Date(year, month - 1, day);
      return date >= minDate && date <= maxDate;
    }, `Date must be between ${formatDate(minDate)} and ${formatDate(maxDate)}`)
});

<RHFInputGroup label="Birth Date" required>
  <RHFDateInput name="rangeValidationBirthDate" placeholder="MM/DD/YYYY" format="MM/DD/YYYY" />
</RHFInputGroup>

Disabled State

MM/DD/YYYY
//
<RHFDateInput name="disabledFixedDate" disabled format="MM/DD/YYYY" />

With Custom Callback

MM/DD/YYYY
//
const handleDateChange = (value: string) => {
  console.log('Date changed:', value);
};

<RHFDateInput
  name="callbackAppointmentDate"
  placeholder="MM/DD/YYYY"
  format="MM/DD/YYYY"
  onChange={handleDateChange}
/>

Complete Form Example

MM/DD/YYYY
//
MM/DD/YYYY
//
import { useForm, FormProvider } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { RHFInput, RHFDateInput, RHFInputGroup, Button } from '@geckoui/geckoui';

const schema = z.object({
  formCheckInDate: z.string()
    .min(1, 'Check-in date is required')
  formCheckOutDate: z.string()
    .min(1, 'Check-out date is required')
  formGuestName: z.string().min(2, 'Guest name is required')
}).refine((data) => {
  if (!data.formCheckInDate || !data.formCheckOutDate) return true;
  const [inMonth, inDay, inYear] = data.formCheckInDate.split('/').map(Number);
  const [outMonth, outDay, outYear] = data.formCheckOutDate.split('/').map(Number);
  const checkIn = new Date(inYear, inMonth - 1, inDay);
  const checkOut = new Date(outYear, outMonth - 1, outDay);
  return checkOut > checkIn;
}, {
  message: 'Check-out date must be after check-in date',
  path: ['formCheckOutDate']
});

function BookingForm() {
  const methods = useForm({
    resolver: zodResolver(schema),
    mode: 'onBlur',
    defaultValues: {
      formCheckInDate: '',
      formCheckOutDate: '',
      formGuestName: ''
    }
  });

  return (
    <FormProvider {...methods}>
      <form onSubmit={methods.handleSubmit(onSubmit)} className="space-y-4">
        <RHFInputGroup label="Guest Name" required>
          <RHFInput name="formGuestName" placeholder="Enter your name" />
        </RHFInputGroup>

        <RHFInputGroup label="Check-in Date" required>
          <RHFDateInput name="formCheckInDate" placeholder="MM/DD/YYYY" format="MM/DD/YYYY" />
        </RHFInputGroup>

        <RHFInputGroup label="Check-out Date" required>
          <RHFDateInput name="formCheckOutDate" placeholder="MM/DD/YYYY" format="MM/DD/YYYY" />
        </RHFInputGroup>

        <Button type="submit">Book Now</Button>
      </form>
    </FormProvider>
  );
}

Inline Rules Validation

For simple validation, use the rules prop:

<RHFDateInput
  name="birthDate"
  rules={{ required: 'Birth date is required' }}
/>

For complex forms, we recommend using a schema resolver (Zod, Yup) instead.

Date Format

RHFDateInput stores and displays dates in MM/DD/YYYY format (US date format).

Formatting Behavior

  • Automatically formats input as user types
  • Adds slashes after month and day
  • Accepts various input formats and normalizes to MM/DD/YYYY
  • Stored value in form state is a string in MM/DD/YYYY format

Validation Pattern

const schema = z.object({
  date: z.string()
    .min(1, 'Date is required')
});

Converting to/from Date Objects

const dateStringToDate = (dateStr: string): Date => {
  const [month, day, year] = dateStr.split('/').map(Number);
  return new Date(year, month - 1, day);
};

const dateToDateString = (date: Date): string => {
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const year = date.getFullYear();
  return `${month}/${day}/${year}`;
};

Error States

RHFDateInput automatically displays error states with:

  • Red border via hasError prop when fieldState.error exists
  • No automatic error icon (you must add via suffix prop if desired)

Use RHFInputGroup component for label + input + error layout:

<RHFInputGroup label="Birth Date" required>
  <RHFDateInput name="basicBirthday" format="MM/DD/YYYY" />
</RHFInputGroup>

Or combine with RHFError component manually:

<RHFDateInput name="basicBirthday" format="MM/DD/YYYY" />
<RHFError name="basicBirthday" />

Tip: Use mode: 'onBlur' in useForm to validate on blur for better UX:

const methods = useForm({
  resolver: zodResolver(schema),
  mode: 'onBlur'
});

Accessibility

  • Inherits all accessibility features from DateInput component
  • Proper ARIA attributes for error states
  • Keyboard navigable
  • Screen reader compatible