React SME Cookbook
All FAQs
formsdecisionchecklistplanningrequirements

Decision Checklist

Here are the 20 main questions to ask first when someone requests a React form, along with concise suggestions based on their answers (updated for React 19 in 2026):

1. What is the purpose of the form?

(login, registration, contact, survey, checkout, settings, etc.)

Suggest: Customize fields, validation, and post-submit flow to match the exact use case. This ensures the form solves the real business need instead of building generic fields that may need heavy rework later.

2. How many fields and what types are needed?

(text, email, password, number, select, checkbox, radio, file, date, textarea, etc.)

Suggest: Prefer uncontrolled inputs with native React 19 features for simpler forms, or use react-hook-form (uncontrolled under the hood) for complex needs. This balances performance with maintainability while leveraging React 19's strengths.

3. Single-page or multi-step form?

Suggest: Single-page for under 8 to 10 fields. Use multi-step with stepper and react-hook-form for longer forms. Multi-step reduces cognitive load and improves completion rates for forms with many fields or conditional logic.

4. What validation rules are required?

(required, format, min/max, password strength, custom logic, real-time versus on-submit)

Suggest: Use react-hook-form with zod for schema-based validation as the best practice for complex cases. For simple forms, combine HTML5 validation with React 19 server actions and useActionState.

5. Where should the data go on submit?

(API endpoint, Firebase, Supabase, local state, email, etc.)

Suggest: Prefer native server actions with useActionState whenever the destination is your own backend — they handle pending state, errors, and progressive enhancement out of the box. For third-party APIs, use the native fetch API inside the action (skip axios in 2026 — it adds bundle size with little benefit now that fetch supports AbortController and streaming).

6. Any special UI/UX or styling requirements?

(Tailwind, shadcn/ui, MUI, Chakra, custom CSS, dark mode, animations)

Suggest: Use shadcn/ui with Tailwind as the most popular and accessible option in 2026. shadcn/ui offers fully customizable, accessible components that look modern without the bundle size overhead of larger UI libraries.

7. Accessibility and mobile requirements?

(ARIA labels, keyboard navigation, screen reader support, responsive design)

Suggest: Use semantic HTML, react-hook-form built-in accessibility, and Tailwind responsive classes. Proper accessibility from the start avoids costly fixes later and ensures compliance with WCAG standards.

8. Should the form support file uploads?

Suggest: Use input type file with react-hook-form and handle with FormData for the API. File uploads require special handling with multipart/form-data, so knowing this early avoids refactoring the submission logic.

9. Do you prefer TypeScript or JavaScript? Any state management preferences?

Suggest: Use TypeScript with react-hook-form and zod as the strongly recommended default for complex forms. TypeScript catches errors early and pairs well with React 19's new hooks.

10. Any tech stack constraints or preferred libraries?

(Next.js versus Vite, existing UI library, form library preference, testing needs)

Suggest: Use Next.js 15 with App Router, TypeScript, react-hook-form, zod, and shadcn/ui unless specified otherwise. This modern stack delivers great performance, SEO benefits, and a smooth development experience for most production forms.

11. Will you use React 19 features like useActionState or useFormStatus?

Suggest: Use useActionState for the submit handler and result (data, error, pending). Use useFormStatus for any nested submit button or pending UI inside the form — it reads the parent form's pending state without prop drilling. They're complementary, not alternatives.

12. Do you plan to use server actions with the form?

Suggest: Integrate native server actions directly in the form action prop. This enables progressive enhancement and seamless server-side handling without manual fetch calls in React 19+.

13. Should the form take advantage of useOptimistic for better UX?

Suggest: Use useOptimistic hook for instant UI feedback on submit. It provides a smooth user experience by showing optimistic updates while the server processes the form data.

14. Any need for useFormState or enhanced form handling in React 19?

Suggest: Note that useFormState was renamed to useActionState in React 19 — same API, new name. Combine it with useFormStatus for automatic pending and error states without third-party libraries for basic cases.

15. Do you want the form to support React 19's improved async handling and transitions?

Suggest: React 19 automatically wraps form action submissions in a transition — no manual startTransition needed for <form action={...}>. Only use explicit startTransition for non-form async work (search, filters, route changes triggered from outside the form).

16. How should local state be managed for form values and UI state?

Suggest: Use uncontrolled inputs with useActionState for simple forms to minimize re-renders. Use react-hook-form for complex forms needing real-time control or validation.

17. Will you need to pre-populate the form with existing data from an API?

Suggest: Avoid useEffect for initial fetching — it causes loading flicker and waterfalls. Prefer fetching in a Server Component and passing data as defaultValues to a Client Component form. For client-side editing flows (e.g. inline edit), use TanStack Query's useQuery then reset() from react-hook-form, or requestFormReset for native uncontrolled forms.

18. How should you handle data fetching during form submission or loading states?

Suggest: In Next.js App Router, server actions usually replace client-side mutations entirely — pending state comes free via useFormStatus. For non-Next.js setups or third-party APIs, use TanStack Query (v5+, formerly React Query) mutations to keep the UI responsive while fetching or updating data.

19. Do you need real-time data synchronization or polling while the form is open?

Suggest: Integrate React Query or SWR for automatic refetching and caching. This keeps form data fresh without manual refresh logic or stale values during long editing sessions.

20. Should local form state sync with global state or external stores?

Suggest: Forms should rarely sync to global state mid-edit — that creates stale-data and validation bugs. Submit results, then update the store (Zustand, Jotai, or Redux Toolkit). Only sync mid-edit for genuine cross-component drafts (e.g. a wizard split across routes).

Quick default recommendation: For simple forms: Native uncontrolled inputs + useActionState + useFormStatus + shadcn/ui + Tailwind in Next.js. For complex forms: TypeScript + react-hook-form + zod + shadcn/ui + Tailwind, optionally combined with React 19 hooks.

This checklist ensures you gather all necessary information upfront to build a form that meets the user's needs while leveraging the latest React 19 features for optimal performance and user experience.

21. Spam, abuse, and bot protection?

Suggest: For public-facing forms (contact, signup, comments), add a honeypot field plus rate limiting in the server action. Add Cloudflare Turnstile or hCaptcha only if you see real abuse — they hurt conversion. Never rely on client-side checks alone.

22. CSRF, auth, and authorization for the action?

Suggest: Server actions in Next.js 15 include built-in CSRF protection for same-origin POSTs. Always re-check auth and authorization inside the server action (don't trust the client gate). Throw or redirect on unauthorized.

23. Auto-save, draft persistence, or "unsaved changes" warning?

Suggest: For long forms (settings, multi-step), debounce-save to localStorage or to the server every few seconds. Use beforeunload (or Next's useBeforeUnload pattern) to warn on dirty state. react-hook-form's formState.isDirty makes this trivial.

24. Field-level error display vs summary vs toast?

Suggest: Inline errors under each field for validation; a summary at the top for screen readers (with aria-live="polite"); toast only for submission-level outcomes (success/server error). Don't show all three for the same error.

25. Mobile input UX (keyboards, autocomplete, input modes)?

Suggest: Set inputMode, autoComplete, and enterKeyHint correctly — inputMode="numeric" for OTP, autoComplete="one-time-code" for SMS codes, autoComplete="email" for email. This single line of attributes dramatically improves mobile completion rates.

26. Internationalization (i18n) of labels and error messages?

Suggest: Keep all user-facing strings (labels, placeholders, validation messages) in your i18n catalog. With Zod, use the errorMap option to translate validation messages, or call your i18n function inside .refine() messages.

27. Analytics, tracking, and abandonment metrics?

Suggest: Track form_start (first focus), form_field_error, form_submit_attempt, and form_submit_success. Abandonment rate by field is the single most valuable form metric — it shows exactly where users give up.

28. Testing strategy for the form?

Suggest: Use Vitest + React Testing Library for unit tests (validation, field interactions). Use Playwright for end-to-end (submit + server-action round-trip + redirect). Test the unhappy paths: validation errors, network failure, race conditions on double-submit.

29. Idempotency and double-submit prevention?

Suggest: Disable the submit button while pending (useFormStatus().pending). For payment or destructive actions, generate an idempotency key on the client and pass it to the server so retries don't duplicate the operation.

30. PII handling, logging, and compliance (GDPR/CCPA/HIPAA)?

Suggest: Never log raw form values in error reporters (Sentry, Datadog) — strip or hash PII before logging. For health/financial data, validate on the server only and avoid storing intermediate state in localStorage.

Cross-references