Input validation
Input validation in Koval is made through built-in validation properties
(required
, pattern
, maxLength
, minLength
, max
, min
)
or a validation state (external validation result or callback function prop),
which supports custom and asynchronous validation.
Koval leverages the native HTMLInputElement error API and browser-integrated error tooltips.
Built-in validation
Textual inputs have these built in validation props: required
, maxLength
, minLength
pattern
.
Textual
Interactive
Interactive inputs support only required
built in validation.
Custom validation
Developers can provide a validation
prop to each input for custom validation. This prop functions as an external state or as a callback, executing each time the input value changes.
External (aka controlled) validation
Don't use internal input validation (pattern
etc) when validation
is set to controlled
mode.
validation
props can accept 4 external validation states: pristine
, valid
, error
and inProgress
.
Validation state | Explanation |
---|---|
pristine | When user didn't interact with input. Empty icon. |
valid | Indicates successfull validation result |
error | Indicates failed validation result |
inProgress | Validation is ongoing. Useful for async validation on server side |
Custom validator function
Internal input validation (pattern
etc) works normally together with validator function.
type validatorFn = (
value: unknown,
validityState: ValidityState,
formState: Record<string, FormDataEntryValue>
) => string | Promise<string>;
The ValidityState interface (opens in a new tab) represents the browser built-in validity states for an input.
formState
is a special object containing full form state, applicable if the input is part of a form. FormDataEntryValue (opens in a new tab) represents a single value from a set of FormData (opens in a new tab) key-value pairs.
Validator can work in either sync (returns string
) or (returns Promise<string>
) async mode. An empty string ''
indicates a successful validation result, while a non-empty string produces an input error with the provided text.
Sync validator
Ideal for complex client-side data validations.
Async validator
Useful for server-side data validation. Runs with a 1000ms debounced delay.
import {InputText} from 'koval-ui';
const validatorFn = async value => {
console.log('Value captured:', value);
await new Promise(resolve => setTimeout(resolve, 1000));
if (value && value.length > 3) {
return `Last captured: ${value}`;
} else {
return '';
}
};
export default function Example() {
return <InputText placeholder="Type to test" validation={validatorFn} />;
}
Override built-in error messages
Custom error messages can be displayed for built-in validations.
const validatorFn = (value: unknown, validityState: ValidityState) => {
if (validityState.valueMissing) {
return 'Please provide value for the input';
} else if (validityState.patternMismatch) {
return 'Please provide valid email';
}
return '';
};
Use complex validation
It is possible to make input validation result
to be dependent on other field value belonging to the same form.
Enable revalidateOnFormChange
prop and use formState
parameter inside validatorFn
.
import { InputText, InputGroup, InputRadio, Button } from 'koval-ui'; const validatorFn = (value, validityState, formState) => { switch (formState['case-selector']) { case 'lowercase': { const isLowerCase = value.toLowerCase() === value; return isLowerCase ? '' : 'Only lower case allowed.' } case 'uppercase': { const isUpperCase = value.toUpperCase() === value; return isUpperCase ? '' : 'Only upper case allowed.' } default: return ''; } }; export default function Example() { return ( <form action="" style={{ display: 'flex', gap: '12px', flexDirection: 'column' }}> <InputGroup name="case-selector"> <InputRadio defaultChecked={true} label="Allow uppercase" value="uppercase" /> <InputRadio label="Allow lowercase" value="lowercase" /> </InputGroup> <InputText revalidateOnFormChange validation={validatorFn} name="text" placeholder="Validated dynamically" /> <Button type="submit">Submit</Button> </form> ); };