Input Field
Text input component integrated with TanStack Form for type-safe form management. Supports tooltips and InputGroup integration for addons and buttons.
npx shadcn@latest add https://shuip.plvo.dev/r/tsf-input-field.json
Preview
InputField
is a text input component that encapsulates TanStack Form's field management with shadcn/ui's design system. It handles all the boilerplate of connecting form state to an input element: wiring event handlers, displaying errors, managing touched states, and rendering consistent UI.
This component is useful when you want to quickly add form inputs without manually setting up form.Field
render props, input bindings, and error display logic for every field.
Built-in features
- Type-safe field names: Uses
DeepKeys<TFormData>
for autocomplete and compile-time validation - Nested path support: Access deeply nested values like
user.profile.email
- Tooltip integration: Optional InfoIcon button with tooltip content via
tooltip
prop - InputGroup ready: Supports shadcn InputGroup for seamless addon integration
- Async validation: Built-in debouncing and loading states for API validation
- Full type inference: Field value types automatically inferred from form schema
Less boilerplate
TanStack Form's standard approach uses render props to access field state:
<form.Fieldname="email"validators={{onChange: ({ value }) => !value.includes('@') ? 'Invalid email' : undefined}}>{(field) => (<><label htmlFor={field.name}>Email</label><inputid={field.name}name={field.name}type="email"value={field.state.value}onChange={(e) => field.handleChange(e.target.value)}onBlur={field.handleBlur}/>{!field.state.meta.isValid && (<span>{field.state.meta.errors.join(', ')}</span>)}</>)}</form.Field>
With InputField
, this reduces to a single declarative component:
<InputFieldform={form}name='email'label='Email'props={{ type: 'email' }}formProps={{validators: {onChange: ({ value }) => !value.includes('@') ? 'Invalid email' : undefined}}}/>
Common use cases
const form = useForm({defaultValues: {name: '',email: '',age: 0,},onSubmit: async ({ value }) => {await saveData(value)},})// Basic text input<InputFieldform={form}name='name'label='Name'description='Your full name'/>// Email with validation<InputFieldform={form}name='email'label='Email'props={{ type: 'email' }}formProps={{validators: {onChange: ({ value }) =>!value.includes('@') ? 'Invalid email' : undefined}}}/>// With tooltip<InputFieldform={form}name='username'label='Username'tooltip='Username must be unique and 3-20 characters'formProps={{validators: {onChange: ({ value }) =>value.length < 3 ? 'Too short' : undefined}}}/>// Number input<InputFieldform={form}name='age'label='Age'props={{ type: 'number', min: 0, max: 120 }}/>
Examples
Async Validation
Default
Nested Path
Tooltip
Props
Name | Type | Description |
---|---|---|
form | ReactFormApi<TFormData> | Form instance from useForm hook |
name | DeepKeys<TFormData> | Type-safe field name (supports nested paths like "user.email") |
label | string? | Field label text |
description | string? | Helper text displayed below the input |
tooltip | React.ReactNode? | Tooltip content displayed in an info icon button |
formProps | Partial<FieldOptions>? | TanStack Form field options (validators, etc.) |
fieldProps | React.ComponentProps<typeof Field>? | Props passed to the Field wrapper component |
props | React.ComponentProps<'input'>? | Native HTML input props (type, placeholder, disabled, etc.) |