Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 60 additions & 4 deletions docs/framework/react/guides/ui-libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ title: UI Libraries

## Usage of TanStack Form with UI Libraries

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`, `shadcn/ui`, or even plain CSS.
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 `Chakra UI`, `Tailwind`, `Material UI`, `Mantine`, `shadcn/ui`, or even plain CSS.

This guide focuses on `Material UI`, `Mantine`, and `shadcn/ui`, but the concepts are applicable to any UI library of your choice.
This guide focuses on `Chakra UI`, `Material UI`, `Mantine`, and `shadcn/ui`, but the concepts are applicable to any UI library of your choice.

### Prerequisites

Before integrating TanStack Form with a UI library, ensure the necessary dependencies are installed in your project:

- For `Chakra UI`, follow the installation instructions on their [official site](https://chakra-ui.com/docs/get-started/installation)
- For `Material UI`, follow the installation instructions on their [official site](https://mui.com/material-ui/getting-started/).
- For `Mantine`, refer to their [documentation](https://mantine.dev/).
- For `shadcn/ui`, refer to their [official site](https://ui.shadcn.com/).
Expand Down Expand Up @@ -153,8 +154,63 @@ The process for integrating shadcn/ui components is similar. Here's an example u
/>
```

- The integration approach is the same as with Mantine and Material UI.
- The integration approach is the same as with Mantine, Material UI.
- The primary difference lies in the specific shadcn/ui component properties and styling options.
- Note the onCheckedChange property of Checkbox instead of onChange.

The ShadCN library includes a dedicated guide covering common scenarios for integrating TanStack Form with its components: https://ui.shadcn.com/docs/forms/tanstack-form
The ShadCN library includes a dedicated guide covering common scenarios for integrating TanStack Form with its components: [https://ui.shadcn.com/docs/forms/tanstack-form](https://ui.shadcn.com/docs/forms/tanstack-form)

### Usage with Chakra UI

The process for integrating Chakra UI components is similar. Here's an example using Input and Checkbox from Chakra UI:

```tsx
<Field
name="name"
children={({ state, handleChange, handleBlur }) => (
<Input
value={state.value}
onChange={(e) => handleChange(e.target.value)}
onBlur={handleBlur}
placeholder="Enter your name"
/>
)}
/>
<Field
name="isChecked"
children={({ state, handleChange, handleBlur }) => (
<Checkbox.Root
checked={state.value}
onCheckedChange={(details) => handleChange(!!details.checked)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This double negation seems weird for a (seemingly) boolean property. Is this accidental?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @LeCarbonator, thanks for pointing that out!

The double negation (!!) here is intentional. In Chakra v3, the Checkbox’s onCheckedChange provides a CheckedChangeDetails object where checked is typed as:

type CheckedState = boolean | "indeterminate";
interface CheckedChangeDetails {
    checked: CheckedState;
}

Our form state (state.value) expects a strict boolean, so passing details.checked directly would cause this TypeScript error:

Argument of type 'CheckedState' is not assignable to parameter of type 'SetStateAction<boolean>'.
  Type '"indeterminate"' is not assignable to type 'SetStateAction<boolean>'.

Using !!details.checked ensures the value is always a boolean (true for checked, false for unchecked or indeterminate), which satisfies the type checker and avoids runtime issues.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see ... Is this common knowledge for Chakra users, or do you think a comment explaining this would help at that line?

// coerce 'indeterminate' to false

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea 👍

This behavior is documented in the Chakra docs and shown in examples for controlled state and indeterminate checkboxes:

So it should be familiar to Chakra users, but I agree it’s not immediately obvious why the coercion is needed when reading the snippet.

Adding a small comment like you mentioned:

// coerce 'indeterminate' to false

would help clarify the intent. I’m happy to add it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @LeCarbonator, I added a line in docs, I hope that helps: e6a7908 (#1909)

onBlur={handleBlur}
>
<Checkbox.HiddenInput />
<Checkbox.Control />
<Checkbox.Label>Accept terms</Checkbox.Label>
</Checkbox.Root>
)}
/>
```

- The integration approach is the same as with Mantine, Material UI, and shadcn/ui.
- Chakra UI exposes its Checkbox as a composable component with separate `Checkbox.Root`, `Checkbox.Control`, `Checkbox.Label`, and `Checkbox.HiddenInput` parts that you wire together.
- The double negation `!!` is used on `onCheckedChange` to coerce Chakra's `"indeterminate"` state to a boolean, ensuring it matches the form state. See the [Chakra UI Checkbox documentation](https://chakra-ui.com/docs/components/checkbox#indeterminate) for more details.
- Alternatively, Chakra UI offers a pre-composed Checkbox component that works the same way as their standard examples, without requiring manual composition. You can learn more about this closed component approach in the [Chakra UI Checkbox documentation](https://chakra-ui.com/docs/components/checkbox#closed-component).
- The TanStack Form integration works identically with either approach—simply attach the `checked`, `onCheckedChange`, and `onBlur` handlers to your chosen component.

Example using the closed Checkbox component:

```tsx
<Field
name="isChecked"
children={({ state, handleChange, handleBlur }) => (
<Checkbox
checked={state.value}
onCheckedChange={(details) => handleChange(!!details.checked)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above.

onBlur={handleBlur}
>
Accept terms
</Checkbox>
)}
/>
```