Skip to main content

3rd-Party UI Libraries

Life is hard but coding can be easier. The reason we โค๏ธ open-source software (OSS) is because there're many awesome libraries that help us making a better world by software products. React Cool Form bears the faith in mind, it allows us integrate with any 3rd-party UI libraries easily. There're three ways to integrate with an UI library in React Cool Form.

1. Seamless Integration#

Uncontrolled components or components that rely on native input elements (i.e. input, select, and textarea) to work under the hood, we need to do nothing ๐Ÿ˜‚. For example: Material-UI's TextField, Checkbox, and Select, etc.

Edit RCF - Material-UI

import { useForm } from "react-cool-form";
import {
FormControl,
FormControlLabel,
FormLabel,
InputLabel,
TextField,
Select,
Checkbox,
Button,
} from "@material-ui/core";
const App = () => {
const { form, use } = useForm({
defaultValues: { username: "", framework: "", fruit: [] },
onSubmit: (values) => console.log("onSubmit: ", values),
});
const errors = use("errors");
return (
<form ref={form} noValidate>
<TextField
label="Username"
name="username"
required
error={!!errors.username}
helperText={errors.username}
/>
<FormControl>
<InputLabel htmlFor="framework">Framework</InputLabel>
{/* When working with select, we need to enable the native select element or you can use the "NativeSelect" instead */}
<Select inputProps={{ id: "framework", name: "framework" }} native>
<option aria-label="None" value="I'm interesting in..." />
<option value="react">React</option>
<option value="vue">Vue</option>
<option value="angular">Angular</option>
<option value="svelte">Svelte</option>
</Select>
</FormControl>
<FormControl component="fieldset"></FormControl>
<div>
<FormLabel component="legend">Fruit</FormLabel>
<FormControlLabel
control={<Checkbox />}
name="fruit"
value="๐ŸŽ"
label="๐ŸŽ"
/>
<FormControlLabel
control={<Checkbox />}
name="fruit"
value="๐Ÿ‹"
label="๐Ÿ‹"
/>
<FormControlLabel
control={<Checkbox />}
name="fruit"
value="๐Ÿฅ"
label="๐Ÿฅ"
/>
</div>
<Button type="submit" variant="contained" color="primary">
Submit
</Button>
</form>
);
};

2. useControlled Hook#

Controlled components with highly customized and full features like React Select or React Datepicker. We can use React Cool Form's useControlled hook to create a reusable controller component for them in a flexible and performant way.

note

When using the hook (and not working with field-array), a default value is required.

Edit RCF - React Select

import { useForm, useControlled } from "react-cool-form";
import Select from "react-select";
const Field = ({ as, name, ...restProps }) => {
const [fieldProps] = useControlled(name, restProps);
const Component = as;
return <Component {...fieldProps} />;
};
const options = [
{ label: "React", value: "react" },
{ label: "Vue", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
];
const App = () => {
const { form } = useForm({
defaultValues: { framework: "" }, // We must provide a default value for the controlled field
excludeFields: ["#framework"], // Exclude the internal input element of React-Select by ID
onSubmit: (values) => console.log("onSubmit: ", values),
});
return (
<form ref={form}>
<Field
as={Select}
name="framework"
inputId="framework" // Used for excluding the internal input element of React-Select
options={options}
parse={(option) => option.value}
format={(value) => options.find((option) => option.value === value)}
/>
<input type="submit" />
</form>
);
};

3. Do It Yourself#

If the above solutions can't meet your needs then you can set up a custom field with the API of React Cool Form. The following example demonstrates how to combine the useFormState and useFormMethods to DIY a custom field with full validation UX.

Edit RCF - Custom Field

import { useForm, useFormState, useFormMethods } from "react-cool-form";
import { TextField, Button } from "@material-ui/core";
const Field = ({ as, name, onChange, onBlur, ...restProps }) => {
const value = useFormState(`values.${name}`);
const { setValue, setTouched } = useFormMethods();
const Component = as;
return (
<Component
name={name}
value={value}
onChange={(e) => {
setValue(name, e.target.value); // Update the field's value and set it as touched
if (onChange) onChange(e);
}}
onBlur={(e) => {
setTouched(name); // Set the field as touched for displaying error (if it's not touched)
if (onBlur) onBlur(e);
}}
{...restProps}
/>
);
};
const App = () => {
const { form, use } = useForm({
defaultValues: { username: "" },
// excludeFields: ["username"], // You can also exclude the field here
validate: ({ username }) => {
const errors = {};
if (!username.length) errors.username = "Required";
return errors;
},
onSubmit: (values) => console.log("onSubmit: ", values),
});
const errors = use("errors");
return (
<form ref={form} noValidate>
<Field
as={TextField}
label="Username"
name="username" // Used for the "excludeFields" option
required
error={!!errors.username}
helperText={errors.username}
inputProps={{ "data-rcf-exclude": true }} // Exclude the field via the pre-defined data attribute
/>
<Button type="submit" variant="contained" color="primary">
Submit
</Button>
</form>
);
};