Every well-established project should have a philosophy that guides its development. Without a core philosophy, development can languish in endless decision-making and have weaker APIs as a result.
This document outlines the core principles that drive the development and feature-set of TanStack Form.
APIs come with tradeoffs. As a result, it can be tempting to make each set of tradeoffs available to the user through different APIs. However, this can lead to a fragmented API that is harder to learn and use.
While this may mean a higher learning curve, it means that you don't have to question which API to use internally or have higher cognitive overhead when switching between APIs.
TanStack Form is designed to be flexible and customizable. While many forms may conform to similar patterns, there are always exceptions; especially when forms are a core component of your application.
As a result, TanStack Form supports multiple methods for validation:
In a world where controlled vs uncontrolled inputs are a hot topic, TanStack Form is firmly in the controlled camp.
This comes with a number of advantages:
You should never need to pass a generic or use an internal type when leveraging TanStack Form. This is because we've designed the library to inference everything from runtime defaults.
When writing sufficiently correct TanStack Form code, you should not be able to distinguish between JavaScript usage and TypeScript usage, with the exception of any type casts you might do of runtime values.
Instead of:
useForm<MyForm>()
useForm<MyForm>()
You should do:
useForm({
defaultValues: {
name: 'Bill Luo',
age: 24,
} as MyForm,
})
useForm({
defaultValues: {
name: 'Bill Luo',
age: 24,
} as MyForm,
})
One of the main objectives of TanStack Form is that you should be wrapping it into your own component system or design system.
To support this, we have a number of utilities that make it easier to build your own components and customized hooks:
// Exported from your own library with pre-bound components for your forms.
export const { useAppForm, withForm } = createFormHook(/* options */)
// Exported from your own library with pre-bound components for your forms.
export const { useAppForm, withForm } = createFormHook(/* options */)
Without doing so, you're adding substantially more boilerplate to your apps and making your forms less consistent and user-friendly.
Your weekly dose of JavaScript news. Delivered every Monday to over 100,000 devs, for free.