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 IntegrationUncontrolled 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.
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> );};
useControlled Hook#
2.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.
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 YourselfIf 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.
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> );};