Checkbox Field
Checkbox component integrated with TanStack Form for type-safe boolean field management.
npx shadcn@latest add https://shuip.plvo.dev/r/tsf-checkbox-field.json
pnpm dlx shadcn@latest add https://shuip.plvo.dev/r/tsf-checkbox-field.json
bun x shadcn@latest add https://shuip.plvo.dev/r/tsf-checkbox-field.json
import type {DeepKeys,DeepValue,FieldAsyncValidateOrFn,FieldOptions,FieldValidateOrFn,FormAsyncValidateOrFn,FormValidateOrFn,ReactFormApi,} from '@tanstack/react-form';import { Checkbox } from '@/components/ui/checkbox';import { Field, FieldDescription, FieldError, FieldLabel } from '@/components/ui/field';export interface CheckboxFieldProps<TFormData,TName extends DeepKeys<TFormData>,TData extends DeepValue<TFormData, TName> = DeepValue<TFormData, TName>,> {form: ReactFormApi<TFormData,undefined | FormValidateOrFn<TFormData>,undefined | FormValidateOrFn<TFormData>,undefined | FormAsyncValidateOrFn<TFormData>,undefined | FormValidateOrFn<TFormData>,undefined | FormAsyncValidateOrFn<TFormData>,undefined | FormValidateOrFn<TFormData>,undefined | FormAsyncValidateOrFn<TFormData>,undefined | FormValidateOrFn<TFormData>,undefined | FormAsyncValidateOrFn<TFormData>,undefined | FormAsyncValidateOrFn<TFormData>,any>;name: TName;label: string;description?: string;formProps?: Partial<FieldOptions<TFormData,TName,TData,undefined | FieldValidateOrFn<TFormData, TName, TData>,undefined | FieldValidateOrFn<TFormData, TName, TData>,undefined | FieldAsyncValidateOrFn<TFormData, TName, TData>,undefined | FieldValidateOrFn<TFormData, TName, TData>,undefined | FieldAsyncValidateOrFn<TFormData, TName, TData>,undefined | FieldValidateOrFn<TFormData, TName, TData>,undefined | FieldAsyncValidateOrFn<TFormData, TName, TData>,undefined | FieldValidateOrFn<TFormData, TName, TData>,undefined | FieldAsyncValidateOrFn<TFormData, TName, TData>>>;fieldProps?: React.ComponentProps<typeof Field>;props?: React.ComponentProps<typeof Checkbox>;}export function CheckboxField<TFormData,TName extends DeepKeys<TFormData>,TData extends DeepValue<TFormData, TName> = DeepValue<TFormData, TName>,>({ form, name, label, description, formProps, fieldProps, props }: CheckboxFieldProps<TFormData, TName, TData>) {return (<form.Field name={name} {...formProps}>{(field) => {const { isValid, errors } = field.state.meta;return (<Field className='gap-2' data-invalid={!isValid} {...fieldProps}><div className='flex items-center gap-2'><Checkboxname={field.name}checked={field.state.value as boolean}onCheckedChange={(checked) => field.handleChange(checked as TData)}onBlur={field.handleBlur}aria-invalid={!isValid}{...props}/><FieldLabel htmlFor={field.name} className='text-sm cursor-pointer'>{label}</FieldLabel></div>{!isValid && (<FieldError className='text-xs text-left' errors={errors.map((error) => ({ message: error }))} />)}{description && <FieldDescription className='text-xs'>{description}</FieldDescription>}</Field>);}}</form.Field>);}
Loading...
Checkboxes are binary inputs for opting in or accepting terms. CheckboxField combines Radix UI's Checkbox with an inline clickable label, making the entire label area interactive—not just the checkbox itself.
Common patterns include required checkboxes for terms acceptance (validated with !value check) or grouped checkboxes for multi-select options (using nested field paths like features.notifications).
Built-in features
- Clickable inline label positioned next to checkbox
- Boolean field type for true/false state
- Required validation for terms acceptance
- Nested paths for grouped checkboxes
Required checkbox
<CheckboxField
form={form}
name='terms'
label='I accept the terms and conditions'
formProps={{
validators: {
onChange: ({ value }) =>
!value ? 'You must accept the terms' : undefined
}
}}
/>Examples
Dependent Fields
Loading...
'use client';import { useForm, useStore } from '@tanstack/react-form';import { CheckboxField } from '#/registry/ui/tsf-checkbox-field';import { InputField } from '@/components/ui/shuip/tanstack-form/input-field';import { SubmitButton } from '@/components/ui/shuip/tanstack-form/submit-button';export default function TsfCheckboxFieldDependentFieldsExample() {const form = useForm({defaultValues: {customShipping: false,shippingAddress: '',sameAsBilling: false,billingAddress: '',},onSubmit: async ({ value }) => {await new Promise((resolve) => setTimeout(resolve, 1000));alert(JSON.stringify(value, null, 2));},});const customShipping = useStore(form.store, (state) => state.values.customShipping);const sameAsBilling = useStore(form.store, (state) => state.values.sameAsBilling);return (<formonSubmit={(e) => {e.preventDefault();form.handleSubmit();}}className='space-y-4'><InputFieldform={form}name='billingAddress'label='Billing Address'formProps={{validators: {onChange: ({ value }) => (!value ? 'Billing address is required' : undefined),},}}/><CheckboxFieldform={form}name='customShipping'label='Use a different shipping address'formProps={{listeners: {onChange: ({ value }) => {if (!value) {form.setFieldValue('shippingAddress', '');form.setFieldValue('sameAsBilling', false);}},},}}/>{customShipping && (<div className='space-y-4 pl-6 border-l-2'><CheckboxFieldform={form}name='sameAsBilling'label='Same as billing address'formProps={{listeners: {onChange: ({ value }) => {if (!value) {form.setFieldValue('shippingAddress', '');} else {form.setFieldValue('shippingAddress', form.getFieldValue('billingAddress'));}},},}}/><InputFieldform={form}name='shippingAddress'label='Shipping Address'props={{ disabled: sameAsBilling }}formProps={{validators: {onChange: ({ value }) => {if (!value && customShipping) return 'Shipping address is required';return undefined;},},}}/></div>)}<SubmitButton form={form}>Submit Order</SubmitButton></form>);}
Default
Loading...
'use client';import { useForm } from '@tanstack/react-form';import { CheckboxField } from '@/components/ui/shuip/tanstack-form/checkbox-field';import { SubmitButton } from '@/components/ui/shuip/tanstack-form/submit-button';export default function TsfCheckboxFieldExample() {const form = useForm({defaultValues: {termsExample: false,marketingExample: false,},onSubmit: async ({ value }) => {await new Promise((resolve) => setTimeout(resolve, 1000));alert(JSON.stringify(value, null, 2));},});return (<formonSubmit={(e) => {e.preventDefault();form.handleSubmit();}}className='space-y-4'><CheckboxFieldform={form}name='termsExample'label='I accept the terms and conditions'formProps={{validators: {onChange: ({ value }) => (!value ? 'You must accept the terms and conditions' : undefined),},}}/><CheckboxFieldform={form}name='marketingExample'label='Send me promotional emails'description='Optional: Receive updates about new features'/><SubmitButton form={form} /></form>);}
Group
Loading...
'use client';import { useForm } from '@tanstack/react-form';import { CheckboxField } from '#/registry/ui/tsf-checkbox-field';import { SubmitButton } from '@/components/ui/shuip/tanstack-form/submit-button';export default function TsfCheckboxFieldGroupExample() {const form = useForm({defaultValues: {features: {notifications: false,analytics: false,darkMode: false,apiAccess: false,},},onSubmit: async ({ value }) => {await new Promise((resolve) => setTimeout(resolve, 1000));alert(JSON.stringify(value, null, 2));},});return (<formonSubmit={(e) => {e.preventDefault();form.handleSubmit();}}className='space-y-4'><div className='space-y-3'><h3 className='font-semibold'>Features</h3><p className='text-sm text-muted-foreground'>Select the features you want to enable</p><div className='space-y-3'><CheckboxFieldform={form}name='features.notifications'label='Enable push notifications'description='Receive real-time updates about your activity'/><CheckboxFieldform={form}name='features.analytics'label='Enable analytics tracking'description='Help us improve by sharing usage data'/><CheckboxFieldform={form}name='features.darkMode'label='Enable dark mode'description='Switch to a darker color scheme'/><CheckboxFieldform={form}name='features.apiAccess'label='Enable API access'description='Get programmatic access to your data'/></div></div><SubmitButton form={form}>Save Preferences</SubmitButton></form>);}
Props
Prop
Type