TanStack Form is a headless library, offering you complete flexibility to style it as you see fit. It's compatible with a wide range of UI libraries, including Tailwind
, Material UI
, Mantine
, or even plain CSS.
This guide focuses on Material UI
and Mantine
, but the concepts are applicable to any UI library of your choice.
Before integrating TanStack Form with a UI library, ensure the necessary dependencies are installed in your project:
Material UI
, follow the installation instructions on their official site.Mantine
, refer to their documentation.Note: While you can mix and match libraries, it's generally advisable to stick with one to maintain consistency and minimize bloat.
Here's an example demonstrating the integration of TanStack Form with Mantine components:
import { TextInput, Checkbox } from '@mantine/core'import { useForm } from '@tanstack/react-form'
export default function App() { const { Field, handleSubmit, state } = useForm({ defaultValues: { firstName: '', lastName: '', isChecked: false, }, onSubmit: async ({ value }) => { // Handle form submission console.log(value) }, })
return ( <> <form onSubmit={(e) => { e.preventDefault() handleSubmit() }} > <Field name="firstName" children={({ state, handleChange, handleBlur }) => ( <TextInput defaultValue={state.value} onChange={(e) => handleChange(e.target.value)} onBlur={handleBlur} placeholder="Enter your name" /> )} /> <Field name="isChecked" children={({ state, handleChange, handleBlur }) => ( <Checkbox onChange={(e) => handleChange(e.target.checked)} onBlur={handleBlur} checked={state.value} /> )} /> </form> <div> <pre>{JSON.stringify(state.values, null, 2)}</pre> </div> </> )}
useForm
hook from TanStack and destructure the necessary properties. This step is optional; alternatively, you could use const form = useForm()
if preferred. TypeScript's type inference ensures a smooth experience regardless of the approach.Field
component, derived from useForm
, accepts several properties, such as validators
. For this demonstration, we focus on two primary properties: name
and children
.
name
property identifies each Field
, for instance, firstName
in our example.children
property leverages the concept of render props, allowing us to integrate components without unnecessary abstractions.children
within the Field
component. This approach is entirely type-safe. When integrating with Mantine components, such as TextInput
, we selectively destructure properties like state.value
, handleChange
, and handleBlur
. This selective approach is due to the slight differences in types between TextInput
and the field
we get in the children.Checkbox
, ensuring consistent integration across different UI elements.The process for integrating Material UI components is similar. Here's an example using TextField and Checkbox from Material UI:
<Field name="lastName" children={({ state, handleChange, handleBlur }) => { return ( <TextField id="filled-basic" label="Filled" variant="filled" defaultValue={state.value} onChange={(e) => handleChange(e.target.value)} onBlur={handleBlur} placeholder="Enter your last name" /> ); }} />
<Field name="isMuiCheckBox" children={({ state, handleChange, handleBlur }) => { return ( <MuiCheckbox onChange={(e) => handleChange(e.target.checked)} onBlur={handleBlur} checked={state.value} /> ); }} />
Your weekly dose of JavaScript news. Delivered every Monday to over 100,000 devs, for free.