react-tailwind-form-validator
Version:
A lightweight and customizable React form validation library built with Tailwind CSS for modern, responsive, and accessible forms.
74 lines (73 loc) • 3.23 kB
JSX
import clsx from 'clsx';
import React, { useState } from 'react';
import { FormProvider } from '../context/FormContext';
import { useFormData } from '../hooks/useFormData';
import { capitalizeFirstLetter, debounce, validateDate, validateEmail, validateNumber, validatePassword, } from '../utils/index';
const DEFAULT_VALIDATIONS = {
email: validateEmail,
password: (value) => validatePassword(value, 'max'),
number: validateNumber,
date: validateDate,
text: () => '',
};
const Input = ({ type, className, placeholder, onValidityChange, onChange, security = 'low', fieldKey, required = true, styleVariant = 'default', customValidation, ...props }) => {
const { updateFormData, setInputValidity, areInputsValid } = useFormData();
const [error, setError] = useState('');
const [shake, setShake] = useState(false);
const [isEmpty, setIsEmpty] = useState(false);
const validateInput = (e) => {
const value = e.target.value;
let errorMessage = '';
let valid = true;
if (required && !value) {
errorMessage = `${capitalizeFirstLetter(type)} is required`;
valid = false;
setIsEmpty(true);
}
else {
setIsEmpty(false);
const defaultValidation = DEFAULT_VALIDATIONS[type];
if (defaultValidation && type !== 'text') {
errorMessage = defaultValidation(value);
}
if (customValidation) {
const customError = customValidation(value);
if (customError) {
errorMessage = customError;
}
}
valid = !errorMessage;
}
setError(errorMessage);
setShake(!valid);
updateFormData(fieldKey, value);
setInputValidity(fieldKey, valid);
if (onChange) {
onChange(e);
}
if (!valid) {
setTimeout(() => setShake(false), 500);
}
if (onValidityChange) {
onValidityChange(valid);
}
};
const inputClass = clsx('rounded-md px-4 py-2 font-semibold text-md transition-all duration-300 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-offset-slate-50 focus:px-2 border-2 border-gray-400', 'bg-[linear-gradient(110deg,#000103,45%,#1e2631,55%,#000103)] bg-[length:200%_100%] animate-shimmer', {
'text-white border-transparent focus:px-2': true,
'focus:ring-[#000103]': type === 'email' || type === 'password',
'focus:ring-[#1e2631]': type === 'number' || type === 'date',
'hover:px-2 focus:px-2': true,
'border-2 border-red-500': !areInputsValid || isEmpty,
'animate-shake': shake,
}, className);
const displayPlaceholder = placeholder || capitalizeFirstLetter(type);
return (<FormProvider>
<input type={type} {...props} className={inputClass} placeholder={displayPlaceholder} onChange={debounce(validateInput, 800)} required={required}/>
{error && (<span className={clsx('text-red-500 text-sm font-semibold', {
'animate-shake': shake,
})}>
{error}
</span>)}
</FormProvider>);
};
export default Input;