Table of Contents
Field
field
- Type
- Description
- Members
checkbox: (initialChecked: boolean = false) => CheckboxField
color: (initialValue: string = "") => TextField
date: (initialValue: string = "") => TextField
datetimeLocal: (initialValue: string = "") => TextField
email: (initialValue: string = "") => TextField
image: (initialValue: string = "") => TextField
month: (initialValue: string = "") => TextField
number: (initialValue: string = "") => TextField
password: (initialValue: string = "") => TextField
radio: (initialValue: string = "") => RadioField
range: (initialValue: string = "") => TextField
search: (initialValue: string = "") => TextField
tel: (initialValue: string = "") => TextField
text: (initialValue: string = "") => TextField
time: (initialValue: string = "") => TextField
url: (initialValue: string = "") => TextField
week: (initialValue: string = "") => TextField
textarea: (initialValue: string = "") => TextAreaField
select: (initialValue: string = "") => SelectField
raw: <ValueType>(initialValue: ValueType) => RawField
addField
createForm
Validator
FormConfig
- Type
- Description
- Generic types
- Members
validateAfterTouchOnChange: () => FormConfig
validateOnChange: () => FormConfig
validateOnSubmit: () => FormConfig
validateOnContextChange: (validate: boolean = true) => FormConfig
withInitialValues: (values: Partial<ValuesType>) => FormConfig
withContext: (context: any) => FormConfig
withValidation: (validations: Validations) => FormConfig
withCustomValidator: (validator: Validator) => FormConfig
useFluentForm
- Type
- Description
- Return type
values: ValuesType
touched: StateTouched
validity: StateValidity
errors: ErrorsType<ValuesType, ErrorType>
context: any
submitting: boolean
fields: Fields<ValuesType>
setValues: (values: Partial<ValuesType>) => void
setInitialValues: (values: Partial<ValuesType>) => void
setContext: (context: Partial<ValuesType>) => void
handleSubmit: (success?: Function, failure?: Function, options?: HandleSubmitOptions) => (event: any) => void
reset: () => void
abtract class
This is the base class of all fields. Custom fields need to extend this class or any subclass.
ValueType
Type of the maintained value
ComponentProps
Type of component props after mapping functions/state of useFluenForm
passed to mapToComponentProps
(see below)
NOTE: Most member functions return
this
to enable fluent API.
Configures field to trigger validation once it was touched, then always if it has changed and on submit.
This is the default
validation trigger.
Configures field to trigger validation everytime it has changed and on submit.
Configures field to trigger validation only on submit.
Since this function is abstract
it needs to be implemented by each subclass.
This member is only relevant when adding custom fields and receives a parameter with following properties:
value: ValueType
: the current value stored in state ofuseFluentForm
. Map this to the value prop of your component.setValue(v: ValueType)
: whenever your component changed its value, this function should be called (often it's anonChange
-like event)setTouched(value: boolean = true)
: call this function when your component has been touched. For most cases this function should be called when theonBlur
event was triggered.
Following is an example implementation of a clearable custom text field, which makes use of mapToComponentProps
.
import React from "react";
import { Field } from "react-fluent-form";
export type ClearableTextFieldProps = {
value: string;
clearable: boolean;
onBlur: () => void;
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
onClear: () => void;
};
export class ClearableTextField extends Field<string, ClearableTextFieldProps> {
private clearable: boolean;
constructor(initialValue = "") {
super(initialValue);
this.clearable = true;
}
// add functions to configure your field
// NOTE: configuration functions should always return "this" to stay conform to the fluent API syntax
public isClearable = (value: boolean = true) => {
this.clearable = value;
return this;
};
public mapToComponentProps: ComponentPropsMapper<
string,
ClearableTextFieldProps
> = ({ value, setValue, setTouched }) => ({
value,
clearable: this.clearable,
onBlur: () => {
setTouched();
},
onChange: e => {
setValue(e.target.value);
},
onClear: () => {
setValue("");
}
});
}
It's recommended to add custom fields using addField
.
Instance of FieldCreator
field
is responsible for creating fields required by createForm
/FormConfig
.
It specifies a member function for each HTML input
type, select
and textarea
. There is also a function for raw
fields. A custom field can be attached using addField
.
For input
s use following members:
For select
, textarea
and raw
use following members:
NOTE: For
raw
fields an initial value is required!
(fieldName: string, (...args: any[]) => Field) => void
Adds a custom field to field
(FieldCreator.prototype
) so it can be used just like the pre-defined fields. addField
statments should be placed in a top level file.
import { addField } from "react-fluent-form";
// only necessary for typescript because types need to be known at compile time
declare module "react-fluent-form" {
interface FieldCreator {
clearableText: (initalValue: string) => ClearableTextField;
}
}
addField("clearableText", intialValue => new ClearableTextField(initialValue));
Usage:
const formConfig = createForm()({
username: field.clearableText("initial value").isClearable(false)
});
<ValuesType>() => (fields: Fields) => FormConfig
creatForm
is a curried function that can be used to create an instance of FormConfig
.
Why is it curried?
Typescript has a missing feature calledpartial type argument inference
which has some work arrounds, one of them is to use curried functions. This issue is well known and part of typescript current roadmap. Once this feature is introduced the API will be changed accordingly.
ValuesType
Type of field values.
field: Fields
Object of fields (s. Field for configuration details).
Needs to match with properties of ValuesType
.
type RegistrationForm = { username: string; password: string };
const formConfig = createForm<RegistrationForm>()({
username: field.text(),
password: field.password()
});
// values will be of type RegistrationForm
const { values } = useFluentForm(formConfig);
abstract calss
Base class of DefaultValidator
, which is used for form validation by default (s. withValidation
below). Can be extended to add custom validator (s. withCustomValidator
below).
ValuesType
Type of field values.
Errors
Type of errors object. Needs to extend ErrorsType
.
abstract validateField: <K extends keyof ValuesType>(field: K, values: ValuesType, context?: any) => Errors[K] | void
Validates one form field and returns validation error for field in case of validation failure else nothing. Needs to be overriden when custom validator is required.
Validates all fields based on validateField
. Can be overriden to e.g. improve performance.
class
Stores configuration of form like validation and fields. It's the only argument that needs to be passed to useFluentForm.
It's recommended to use createForm to create a form config.
ValuesType
Type of field values.
NOTE: Every member function returns
this
to enable fluent API.
IMPORTANT:
Validation triggers defined onField
level are always considered first.FormConfig
level validation triggers will only be used when no trigger is defiend onField
level.
Configures validation for all fields to trigger once they touched, then always if they have changed and on submit.
This is the default
validation trigger.
Configures validation for all fields to trigger everytime they have changed and on submit.
Configures validation for all fields to trigger only on submit.
Configures validation for all fields to be triggered when context has changed. The default value is false
.
Context changes are triggerd by setContext
function return by useFluentForm
.
While initial values can be set on Field
level (e.g. field.text("initial")
) it's also possible to do so on FormConfig
level for all fields.
const formConfig = createForm<UserForm>()({
username: field.text("initial"),
email: field.email()
}).withInitialValues({ email: "[email protected]" });
Sets the initial context value. It needs to be an object of any type.
It's recommend to wrap your context values in a context
field (s. withValidation
below for more details):
const formConfig = createForm<UserForm>()({
username: field.text(),
email: field.email()
}).withContext({
context: {
// values are wrapped here
shouldValidateUsername: true
}
});
Adds functionality to validate the form. A yup.Schema
or a custom validate function
can be provided for each field. Behind the scenes DefaultValidator
is being used.
A validate function
receives following values as paramater:
value
: current value of fieldvalues
: current values of all fields in the formcontext
: current context value
Using a yup.Schema
will always result in an string[]
error type.
In contrast to that validate function
allow any kind of error type to be returned. Returning nothing (undefined
) will indicate that there is no validation error.
On top of that also a yup.Schema
can be return by a validate functions
which enables conditional yup.Schema
validation. In this case the error type will also be from type string[]
. To say it in other words: returning a yup.Schema
in a validate function
will result in an evaulation of the returned yup.Schema
.
IMPORTANT:
When usingyup validation
other form fields need to be accessed with a leading$
(here$lastName
) which usually means the value is coming from the context. In fact other form values are passed as context to theyup schema
for each field during validation execution.
To clearly seperate context values from field values it's recommened to wrap actual context values in acontext
field (as mentioned inwithContext
)
formConfig.withValidation({
username: yup.string().required(),
firstName: yup.string().when("$lastName", {
is: "",
otherwise: yup.string().required()
}),
lastName: yup.string(),
// the error type will be "string | string[]" for this validate function
password: (value, values, _context) => {
if (value.includes(values.username)) {
return "Password should not contain username";
} else {
return yup
.string()
.required()
.matches(/[a-zA-Z]/, "Password can only contain letters.");
}
}
});
Allows to provide a custom Validator
.
Providing such will remove DefaultValidator
, thus removes all features mentioned in withValdation
.
Following is an example of a simple validator that does truthy checks on fields:
import { Validator, ErrorsType } from "react-fluent-form";
export class RequiredValidator<ValuesType> extends Validator<
ValuesType,
ErrorsType<string>
> {
constructor(requiredFields) {
super();
this.requiredFields = requiredFields;
}
public validateField<K extends keyof ValuesType>(
field: K,
values: ValuesType,
_context: any // not relevant for this example
) {
if (this.requiredFields[field] && !values[field]) {
return "field is required";
}
}
}
Usage:
const formConfig = createForm()({
username: field.text(),
email: field.email(),
phone: field.tel()
}).withCustomValidator(new RequiredValidator({
username: true,
email: true
});
<Config extends FormConfig>(config: Config) => FluentFormReturnType
Core react hook of this library.
Expects only a FormConfig
as parameter:
// ValuesType
type RegistrationForm = { username: string; password: string };
const formConfig = createForm<RegistrationForm>()({
username: field.text(),
password: field.password()
});
const {
values,
touched,
validity,
errors,
context,
submitting,
fields,
setValues,
setInitialValues,
setContext,
handleSubmit,
reset
} = useFluentForm(formConfig);
Contains current values of form. Initial values are comming from FormConfig
Contains information about the touched state of each field.
Initial value is {}
.
Usually field are touched once onBlur
event was triggered for the field.
This can help to trigger validations depended on the specified validation trigger.
Possible values for each field:
undefined
: field was not touched yettrue
: field was touched
{
username: true,
password: undefined
}
Contains information about the validation state of each field. Initial value is {}
.
Possible values for each field:
undefined
: validation was not triggert yettrue
: field is validfalse
: field is invalid
{
username: true,
password: false
}
Contains errors for each field resulted from it's validation. Initial value is {}
.
Possible values for each field:
undefined
: field has no error or was not validated yet- For
yup.Schema
's theErrorType
will always bestring[]
- For
validate function
's theErrorType
could possibly be anything
{
username: ["username is a required field"],
password: 1 // only possible with validate function
}
Current context value. Initial value is undefined
.
true
if form is currently submitting else false
.
Contains props for each component which resulted from evaluation of mapToComponentProps
member function of each field (s. Field
).
const formConfig = createForm<RegistrationForm>()({
username: field.text(), // field.text() has a mapToComponentProps function
password: field.password() // just like field.password() and all other fields have
});
const MyForm = () => {
const { fields } = useFluentForm(fromConfig);
return (
<input {...fields.username}/>
<input {...fields.password}/>
)
}
Sets values of form.
Sets initial values of form. This is important when resetting a form.
Updates value of validation context. To re-validate all fields on context change FormConfig.validateOnContextChange
can be used.
Works well in combinations with useEffect
.
const { setContext } = useFluentForm(formConfig.validateOnContextChange());
useEffect(() => {
setContext({ context: coordinates });
}, [coordinates]);
handleSubmit: (success?: Function, failure?: Function, options?: HandleSubmitOptions) => (event: any) => void
Returns a submit handler. When this handler is called validation for all fields will be trigger no matter which validation trigger was configured.
Following parameter can be passed:
success
: a callback when the validation was successfulfailure
: a callback when the validation has failedoptions
preventDefault
: will callpreventDefault
function in case submit handler passes an event. Default value istrue
stopPropagation
: will callstopPropagation
function in case submit handler passes an event. Default value istrue
formConfig.withValidation({
username: yup.string().required(),
password: yup.string().required().min(8)
}
});
function LoginForm() {
const {
values,
touched,
validity,
errors,
fields,
handleSubmit
} = useFluentForm(formConfig);
const handleSubmitSuccess = () => console.log(values);
const handleSubmitFailure = () => console.log(errors);
return (
<form onSubmit={handleSubmit(
handleSubmitSuccess,
handleSubmitFailure,
// these are default options
{ preventDefault: true, stopPropagtion: true }
)}>
<input {...fields.username} />
<input {...fields.password} />
<button type="submit">Submit</button>
</form>
);
}
Sets complete form state to inital state. Initial values can be modified using setInitialValues
.