reactjsvalidationinputreact-datepicker

DatePicker: Dynamic Border Color Based on Validation


I'm using react-datepicker and react-input-mask to create a controlled date input. I want to update the input border color dynamically:

  1. Default state: Initial styles.

  2. On focus: When the input is empty, the border should be purple.

  3. The border should turn red if the input is invalid (e.g., incomplete date).

  4. If valid: the Border should turn green.

      <Controller
     control={control}
     name={name}
     rules={{
       validate: (value) => {
         if (!value) return 'Date is required';
         const cleanedValue = value.replace(/_/g, '').trim();
         if (cleanedValue.length < 10) return 'Incomplete date';
         const parsedDate = parse(cleanedValue, 'MM/dd/yyyy', new Date());
         if (!isValid(parsedDate)) return 'Invalid date format';
         return true;
       },
     }}
     render={({ field, fieldState }) => {
       const isInvalid =
         fieldState.error ||
         field.value.includes('_') ||
         field.value.length < 10;
    
       return (
         <span
           className={`input ${isInvalid ? 'error' : field.value ? 'valid' : ''}`}
           style={{
             borderColor: isInvalid
               ? 'red'
               : field.value
                 ? 'green'
                 : '#9095A1',
             boxShadow: isInvalid
               ? '0 0 5px rgb(201,23,23)'
               : field.value
                 ? '0 0 5px rgb(40,224,24)'
                 : 'none',
           }}
         >
           {IconLeft && <span className="icon">{IconLeft}</span>}
    
           <DatePicker
             disabled={disabled}
             shouldCloseOnSelect={true}
             placeholderText={placeholder}
             selected={
               field.value.length === 10
                 ? parse(field.value, 'MM/dd/yyyy', new Date())
                 : null
             }
             minDate={minDate}
             maxDate={maxDate}
             onChange={(date) => {
               const formattedDate = date ? format(date, 'MM/dd/yyyy') : '';
               field.onChange(formattedDate);
             }}
             customInput={
               <InputMask
                 mask="99/99/9999"
                 value={field.value || ''}
                 onChange={(e) => field.onChange(e.target.value)}
                 onFocus={(e) => {
                   e.target.style.borderColor = 'purple';
                   e.target.style.boxShadow = '0 0 5px purple';
                 }}
                 onBlur={(e) => {
                   if (
                     field.value.includes('_') ||
                     field.value.length < 10
                   ) {
                     field.onChange('');
                   }
                   e.target.style.borderColor = isInvalid
                     ? 'red'
                     : field.value
                       ? 'green'
                       : 'initial';
                   e.target.style.boxShadow = isInvalid
                     ? '0 0 5px rgb(201,23,23)'
                     : field.value
                       ? '0 0 5px rgb(40,224,24)'
                       : 'none';
                 }}
                 disabled={disabled}
               />
             }
           />
    
           {IconRight && <span className="icon">{IconRight}</span>}
         </span>
       );
     }}
    

    />


Solution

  • Since no one answered my question, I found the solution myself and am sharing it with others. This is a helper function that should used in Controller to set dynamic classNames and do not forget to set rules={{requier: true}}

     export const getDynamicValidationColors = (field: { value: any }): string => {
      if (field.value?.length === 0) {
        return 'validatedPurple';
      } else if (field.value) {
        return 'validatedGreen';
      } else {
        return 'validatedPurple';
      }
    };