|
| 1 | +--- |
| 2 | +title: Announcing TanStack Form v1 |
| 3 | +published: 03/03/2025 |
| 4 | +authors: |
| 5 | + - Corbin Crutchley |
| 6 | +--- |
| 7 | + |
| 8 | +We're excited to announce the first stable version of [TanStack Form](/form/v1) is live and ready for usage in production! 🥳 |
| 9 | + |
| 10 | +We support five frameworks at launch: React, Vue, Angular, Solid, and Lit, as well as a myriad of features for each specific framework. |
| 11 | + |
| 12 | +# How to install |
| 13 | + |
| 14 | +```shell |
| 15 | +$ npm i @tanstack/react-form |
| 16 | +# or |
| 17 | +$ npm i @tanstack/vue-form |
| 18 | +# or |
| 19 | +$ npm i @tanstack/angular-form |
| 20 | +# or |
| 21 | +$ npm i @tanstack/solid-form |
| 22 | +# or |
| 23 | +$ npm i @tanstack/lit-form |
| 24 | +``` |
| 25 | + |
| 26 | +# A bit of history |
| 27 | + |
| 28 | +It was nearly two years ago when [I saw Tanner's BlueSky (an invite-only platform at the time) post announcing that he was working on a new project: TanStack Form](https://bsky.app/profile/tannerlinsley.com/post/3ju5z473w5525). |
| 29 | + |
| 30 | + |
| 31 | + |
| 32 | +At the time, I had just launched an alternative form library for React called "[HouseForm](https://web.archive.org/web/20240101000000*/houseform.dev)" and I was immediately enamored by some of the ideas Tanner's library brought to the table. |
| 33 | + |
| 34 | +I was fortunate enough to attend a hackathon that Tanner was also going to soon after and we were able to get some time to work on integrating some APIs from HouseForm into the project. |
| 35 | + |
| 36 | +Since that time, Tanner's handed much of the reigns of Form over to me and a wonderful group of additional maintainers. |
| 37 | + |
| 38 | +So, what have we built in that time? |
| 39 | + |
| 40 | +# Features |
| 41 | + |
| 42 | +One of the advantages of being in the oven for so long is that TanStack Form launches with a flurry of features you can leverage day one. |
| 43 | + |
| 44 | +Let's go over _just a few_ of them using React's adapter as examples. |
| 45 | + |
| 46 | +## Extreme type safety |
| 47 | + |
| 48 | +Like many all of the TanStack projects, Form has revolutionized what it means to be a "type-safe" form library. |
| 49 | + |
| 50 | +```tsx |
| 51 | +const form = useForm({ |
| 52 | + defaultValues: { |
| 53 | + name: "", |
| 54 | + age: 0 |
| 55 | + } |
| 56 | +}); |
| 57 | + |
| 58 | +// TypeScript will correctly tell you that `firstName` is not a valid field |
| 59 | +<form.Field name="firstName"/> |
| 60 | + |
| 61 | +// TypeScript will correctly tell you that `name`'s type is a `string`, not a `number` |
| 62 | +<form.Field name="name" children={field => <NumberInput value={field.state.value}/>}/> |
| 63 | +``` |
| 64 | + |
| 65 | +We even support type-checking what errors are returned in `<form.Field>`: |
| 66 | + |
| 67 | +```tsx |
| 68 | +<form.Field |
| 69 | + name="age" |
| 70 | + validators={{ |
| 71 | + onChange: ({ value }) => (value < 12 ? { tooYoung: true } : undefined), |
| 72 | + }} |
| 73 | + children={(field) => ( |
| 74 | + <> |
| 75 | + <NumberInput value={field.state.value} /> |
| 76 | + // TypeScript will correctly tell you that `errorMap.onChange` // is an object, |
| 77 | + not a string |
| 78 | + <p>{field.state.meta.errorMap.onChange}</p> |
| 79 | + </> |
| 80 | + )} |
| 81 | +/> |
| 82 | +``` |
| 83 | + |
| 84 | +> Oh, yeah, we support field-based validation as well as form validation. Mix-n-match them! |
| 85 | +
|
| 86 | +The best part? [You won't need to pass any typescript generics to get this level of type safety](/form/latest/docs/philosophy#generics-are-grim). Everything is inferred from your runtime usage. |
| 87 | + |
| 88 | +## Schema validation |
| 89 | + |
| 90 | +Thanks to the awesome work by the creators of [Zod](http://zod.dev/), [Valibot](https://valibot.dev), and [ArkType](https://arktype.io/), we support [Standard Schema](https://github.com/standard-schema/standard-schema) out of the box; no other packages needed. |
| 91 | + |
| 92 | +```tsx |
| 93 | +const userSchema = z.object({ |
| 94 | + age: z.number().gte(13, 'You must be 13 to make an account'), |
| 95 | +}) |
| 96 | + |
| 97 | +function App() { |
| 98 | + const form = useForm({ |
| 99 | + defaultValues: { |
| 100 | + age: 0, |
| 101 | + }, |
| 102 | + validators: { |
| 103 | + onChange: userSchema, |
| 104 | + }, |
| 105 | + }) |
| 106 | + return ( |
| 107 | + <div> |
| 108 | + <form.Field |
| 109 | + name="age" |
| 110 | + children={(field) => { |
| 111 | + return <>{/* ... */}</> |
| 112 | + }} |
| 113 | + /> |
| 114 | + </div> |
| 115 | + ) |
| 116 | +} |
| 117 | +``` |
| 118 | + |
| 119 | +## Async validation |
| 120 | + |
| 121 | +That's not all, though! We also support async functions to validate your code; complete with built-in debouncing and [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)-based cancellation: |
| 122 | + |
| 123 | +```tsx |
| 124 | +<form.Field |
| 125 | + name="age" |
| 126 | + asyncDebounceMs={500} |
| 127 | + validators={{ |
| 128 | + onBlurAsync: async ({ value, signal }) => { |
| 129 | + const currentAge = await fetchCurrentAgeOnProfile({ signal }) |
| 130 | + return value < currentAge ? 'You can only increase the age' : undefined |
| 131 | + }, |
| 132 | + }} |
| 133 | +/> |
| 134 | +``` |
| 135 | + |
| 136 | +## Platform support |
| 137 | + |
| 138 | +Not only do we support multiple frameworks as we mentioned from the start; we support multiple runtimes. Whether you're using React Native, NativeScript, or even SSR solutions like Next.js or [TanStack Start](/start), we have you covered. |
| 139 | + |
| 140 | +In fact, if you're using SSR solutions, we even make server-side form validation a breeze: |
| 141 | + |
| 142 | +```typescript |
| 143 | +// app/routes/index.tsx, but can be extracted to any other path |
| 144 | +import { createServerValidate, getFormData } from '@tanstack/react-form/start' |
| 145 | +import { yourSchemaHere } from '~/constants/forms' |
| 146 | + |
| 147 | +const serverValidate = createServerValidate({ |
| 148 | + ...formOpts, |
| 149 | + onServerValidate: yourSchemaHere, |
| 150 | +}) |
| 151 | + |
| 152 | +export const getFormDataFromServer = createServerFn({ method: 'GET' }).handler( |
| 153 | + async () => { |
| 154 | + return getFormData() |
| 155 | + } |
| 156 | +) |
| 157 | +``` |
| 158 | + |
| 159 | +> This code sample excludes some of the relevant code to keep things glanceable. [For more details on our SSR integration, please check our docs.](/form/latest/docs/framework/react/guides/ssr) |
| 160 | +
|
| 161 | +And boom, the exact same validation logic is running on both your frontend and backend. Your forms will even show errors when JavaScript is disabled on the user's browser! |
| 162 | + |
| 163 | +# A look forward |
| 164 | + |
| 165 | +We're not resting on our laurels, however - we have plans to add new features to v1 now that we're stable. These features include: |
| 166 | + |
| 167 | +- [Persistence APIs](https://github.com/TanStack/form/pull/561) |
| 168 | +- [A Svelte 5 adapter](https://github.com/TanStack/form/issues/516) |
| 169 | +- [Better DX for transforming values on submission](https://github.com/TanStack/form/issues/418) |
| 170 | +- [Form Groups](https://github.com/TanStack/form/issues/419) |
| 171 | + |
| 172 | +And much more. |
| 173 | + |
| 174 | +# Thank **you** |
| 175 | + |
| 176 | +There's so many people I'd like to thank that once I'd gotten started I'd never end. Instead, I'll address each group of folks I want to thank. |
| 177 | + |
| 178 | +- Thank you to our contributors: So many people had to come together to make this happen. From maintainers of other TanStack projects giving us guidance, to drive-by PRs; it all helped us get across the line. |
| 179 | + |
| 180 | +- Thank you to our early adopters: The ones who took a risk on us and provided invaluable feedback on our APIs and functionality. |
| 181 | +- Thank you to the content creators who covered our tools: You brought more eyes to our project - making it better through education and feedback. |
| 182 | +- Thank you to the broader community: Your excitement to use our tools have driven the team immensely. |
| 183 | + |
| 184 | +And finally, thank **you** for taking the time to read and explore our newest tool. ❤️ |
0 commit comments