React SME Cookbook
All FAQs

Search Documentation

Search across all documentation pages

gherkinbddformsdecision-checklistreact-hook-formzod

Gherkin Form Decision Checklist

Write BDD Gherkin scenarios that stakeholders and developers agree on before coding -- using a Cloud Architect Profile form as the realistic example project.

note: The below is an example, there are various valid ways to implement the form. The key is to use Gherkin to lock in the expected behavior before writing any component code.

Keep a balanced level of detail in the scenarios -- enough to specify expected behavior without dictating exact implementation.

The scenarios should be readable by non-technical stakeholders while still providing clear guidance for developers.

Why Gherkin Before Code?

Gherkin scenarios are executable specifications written in plain English (Given/When/Then). They bridge the gap between business requirements and test code:

  • Stakeholders read them as acceptance criteria
  • Developers implement them as automated tests
  • QA uses them as the source-of-truth test plan
  • Everyone agrees on behavior before a single line of component code is written

The Example Project: Cloud Architect Profile Form

A multi-step form where Cloud Architects enter their professional profile:

StepFieldsTypes
1. Personal InfoFull name, email, phone, LinkedIn URLtext, email, tel, url
2. ExperienceYears of experience, current role, certifications (multi-select), bionumber, select, checkbox, textarea
3. Job HistoryCompany name, role, start/end dates, description (repeatable group)text, select, date, textarea
4. SkillsCloud platforms (AWS/Azure/GCP), specialties (multi-select), proficiency ratingcheckbox, select, radio
5. UploadsProfile photo, architecture diagrams, site screenshotsfile (image), file (multiple)
6. Review & SubmitSummary of all steps, edit links, final submitread-only, button

Tech stack: Next.js 15, TypeScript, react-hook-form, zod, shadcn/ui, Tailwind CSS v4


Decision Checklist with Gherkin Scenarios

Each decision below is answered for the Cloud Architect Profile form, followed by the Gherkin scenarios that lock in the expected behavior.


1. What is the purpose of the form?

Decision: Professional profile creation for Cloud Architects -- captures identity, experience, job history, skills, and portfolio uploads for a talent platform.

Why this matters for Gherkin: The purpose drives which fields are required, what validation is critical, and what the post-submit flow looks like.

Feature: Cloud Architect Profile Creation
 
  Background:
    Given the architect is logged in
    And they navigate to "/profile/create"
 
  Scenario: New architect sees empty profile form
    Then they should see a multi-step form with 6 steps
    And step 1 "Personal Info" should be active
    And a progress indicator should show "Step 1 of 6"
 
  Scenario: Completed profile is visible on the platform
    Given the architect has submitted a valid profile
    When a recruiter searches for "AWS Solutions Architect"
    Then the architect's profile should appear in results

Suggested approach: 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?

Decision: 20+ fields across 6 steps -- text, email, tel, url, number, select, multi-select (checkbox group), radio, date, textarea, and file upload.

Feature: Field Types and Input Behavior
 
  Scenario: Personal Info step has correct field types
    Given the architect is on step 1 "Personal Info"
    Then the "Full Name" field should be a text input
    And the "Email" field should be an email input
    And the "Phone" field should be a tel input
    And the "LinkedIn URL" field should be a url input
 
  Scenario: Experience step supports multi-select certifications
    Given the architect is on step 2 "Experience"
    When they check "AWS Solutions Architect Professional"
    And they check "Google Cloud Professional Architect"
    Then both certifications should be selected
    And the selected count should show "2 selected"
 
  Scenario: Job History supports repeatable entries
    Given the architect is on step 3 "Job History"
    When they click "Add Another Position"
    Then a new empty job entry group should appear
    And they should be able to add up to 10 positions
 
  Scenario: Skills step uses radio buttons for proficiency
    Given the architect is on step 4 "Skills"
    When they select "Expert" for AWS proficiency
    Then "Expert" should be selected
    And "Intermediate" and "Beginner" should not be selected

Suggested approach: Use react-hook-form (uncontrolled under the hood) for this complex form with dynamic field arrays. Prefer useFieldArray for the repeatable Job History entries.


3. Single-page or multi-step form?

Decision: Multi-step with 6 steps. 20+ fields would overwhelm users on a single page.

Feature: Multi-Step Navigation
 
  Scenario: Architect progresses through steps
    Given the architect is on step 1 "Personal Info"
    And they have filled in all required fields
    When they click "Next"
    Then step 2 "Experience" should be active
    And the progress indicator should show "Step 2 of 6"
 
  Scenario: Architect navigates back without losing data
    Given the architect is on step 3 "Job History"
    And they have entered "Acme Corp" as company name
    When they click "Back"
    And they click "Next"
    Then the company name field should still contain "Acme Corp"
 
  Scenario: Architect cannot skip ahead past invalid steps
    Given the architect is on step 1 "Personal Info"
    And the "Full Name" field is empty
    When they click step 3 in the progress indicator
    Then step 1 should remain active
    And a validation error should appear on the "Full Name" field
 
  Scenario: Architect can click completed steps to edit
    Given the architect has completed steps 1 through 4
    And they are on step 5 "Uploads"
    When they click step 2 in the progress indicator
    Then step 2 "Experience" should be active
    And all previously entered data should be preserved
 
  Scenario: Progress indicator shows completion status
    Given the architect has completed steps 1 and 2
    And they are on step 3
    Then step 1 should show a checkmark icon
    And step 2 should show a checkmark icon
    And step 3 should show as "current"
    And steps 4 through 6 should show as "upcoming"

Suggested approach: Use multi-step with a stepper component and react-hook-form. Multi-step reduces cognitive load and improves completion rates. Use a single useForm instance across all steps to preserve state.


4. What validation rules are required?

Decision: Schema-based validation with zod -- required fields, format validation, conditional rules, and cross-field validation.

Feature: Form Validation
 
  Scenario: Required fields show errors when empty
    Given the architect is on step 1 "Personal Info"
    And they have not filled in any fields
    When they click "Next"
    Then they should see "Full name is required"
    And they should see "Email is required"
    And the form should not advance to step 2
 
  Scenario: Email format is validated
    Given the architect is on step 1 "Personal Info"
    When they type "not-an-email" in the "Email" field
    And they click "Next"
    Then they should see "Please enter a valid email address"
 
  Scenario: LinkedIn URL must be a valid LinkedIn profile
    Given the architect is on step 1 "Personal Info"
    When they type "https://twitter.com/someone" in the "LinkedIn URL" field
    And they click "Next"
    Then they should see "Please enter a valid LinkedIn profile URL"
 
  Scenario: Years of experience must be a positive number
    Given the architect is on step 2 "Experience"
    When they type "-3" in the "Years of Experience" field
    And they click "Next"
    Then they should see "Years of experience must be 0 or greater"
 
  Scenario: At least one cloud platform must be selected
    Given the architect is on step 4 "Skills"
    And no cloud platforms are checked
    When they click "Next"
    Then they should see "Select at least one cloud platform"
 
  Scenario: Job history dates must be logically valid
    Given the architect is on step 3 "Job History"
    When they set start date to "2025-06-01"
    And they set end date to "2024-01-01"
    And they click "Next"
    Then they should see "End date must be after start date"
 
  Scenario: Bio has a maximum character limit
    Given the architect is on step 2 "Experience"
    When they type 1001 characters in the "Bio" field
    Then they should see "Bio must be 1000 characters or fewer"
    And a character counter should show "1001 / 1000"
 
  Scenario: Real-time validation feedback on email
    Given the architect is on step 1 "Personal Info"
    When they type "alice@" in the "Email" field
    And they move focus to the next field
    Then they should see "Please enter a valid email address"
    When they go back and type "alice@example.com"
    Then the error message should disappear

Suggested approach: Use react-hook-form with zod for schema-based validation. Use mode: "onBlur" for real-time feedback on focus loss. Define one zod schema per step and a combined schema for final submission.


5. Where should the data go on submit?

Decision: Server Action with useActionState -- the form submits to the platform's own backend.

Feature: Form Submission
 
  Scenario: Successful profile submission
    Given the architect has completed all 6 steps with valid data
    When they click "Submit Profile" on the review step
    Then a loading spinner should appear on the submit button
    And the button should be disabled
    And after submission completes they should see "Profile created successfully!"
    And they should be redirected to "/profile/me"
 
  Scenario: Server returns validation errors
    Given the architect submits a profile with a duplicate email
    When the server responds with an error
    Then they should see "This email is already registered"
    And the form should navigate back to step 1
    And the "Email" field should be highlighted
 
  Scenario: Network failure during submission
    Given the architect clicks "Submit Profile"
    And the network request fails
    Then they should see "Something went wrong. Please try again."
    And the submit button should be re-enabled
    And no data should be lost
 
  Scenario: Form data is sent as multipart/form-data
    Given the architect has uploaded a profile photo
    And they have filled all required fields
    When they submit the form
    Then the request should include the photo as a file upload
    And all text fields should be included in the payload

Suggested approach: Use server actions with useActionState for the own backend. Handle pending state, errors, and progressive enhancement out of the box. Use FormData for file uploads.


6. Any special UI/UX or styling requirements?

Decision: shadcn/ui with Tailwind CSS v4, dark mode support, and animated step transitions.

Feature: UI/UX Requirements
 
  Scenario: Form renders with shadcn/ui components
    Given the architect opens the profile form
    Then all inputs should use shadcn/ui styled components
    And buttons should follow the design system
    And the form should have consistent spacing and typography
 
  Scenario: Dark mode support
    Given the system is in dark mode
    When the architect opens the profile form
    Then all form elements should render with dark theme colors
    And contrast ratios should meet WCAG AA standards
 
  Scenario: Step transitions are animated
    Given the architect is on step 1
    When they click "Next"
    Then step 1 should slide out to the left
    And step 2 should slide in from the right
    And the transition should complete within 300ms
 
  Scenario: Form is visually organized with sections
    Given the architect is on step 2 "Experience"
    Then the certifications should be grouped in a card
    And the bio field should span the full width
    And help text should appear below complex fields

Suggested approach: Use shadcn/ui with Tailwind as the most accessible option. shadcn/ui offers fully customizable, accessible components without the bundle size overhead of larger UI libraries.


7. Accessibility and mobile requirements?

Decision: Full WCAG 2.1 AA compliance, keyboard navigation, screen reader support, responsive design.

Feature: Accessibility
 
  Scenario: All fields have accessible labels
    Given the architect is on any form step
    Then every input should have an associated label element
    And every required field should have aria-required="true"
 
  Scenario: Keyboard navigation through form
    Given the architect is on step 1
    When they press Tab
    Then focus should move to the first input field
    And they should be able to Tab through all fields in order
    And they should be able to submit using Enter
 
  Scenario: Screen reader announces validation errors
    Given the architect submits step 1 with empty required fields
    Then each error message should have role="alert"
    And the screen reader should announce the first error
 
  Scenario: Screen reader announces step changes
    Given the architect completes step 1 and moves to step 2
    Then the screen reader should announce "Step 2 of 6: Experience"
 
  Scenario: Mobile responsive layout
    Given the architect is using a mobile device (viewport 375px)
    Then the form should stack fields vertically
    And the progress indicator should be compact
    And touch targets should be at least 44x44 pixels
    And the "Next" and "Back" buttons should be full-width

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


8. Should the form support file uploads?

Decision: Yes -- profile photo (single image), architecture diagrams (multiple images), and site screenshots (multiple images).

Feature: File Uploads
 
  Scenario: Architect uploads a profile photo
    Given the architect is on step 5 "Uploads"
    When they select a JPEG file under 5MB for "Profile Photo"
    Then a thumbnail preview should appear
    And the file name and size should be displayed
 
  Scenario: Profile photo validates file type
    Given the architect is on step 5 "Uploads"
    When they select a .exe file for "Profile Photo"
    Then they should see "Only JPEG, PNG, and WebP files are accepted"
    And the file should not be uploaded
 
  Scenario: Profile photo validates file size
    Given the architect is on step 5 "Uploads"
    When they select a 15MB image for "Profile Photo"
    Then they should see "File must be under 5MB"
 
  Scenario: Architect uploads multiple architecture diagrams
    Given the architect is on step 5 "Uploads"
    When they select 3 PNG files for "Architecture Diagrams"
    Then 3 thumbnail previews should appear
    And each should show a remove button
    And the upload count should show "3 files selected"
 
  Scenario: Architect removes an uploaded file
    Given the architect has uploaded 3 architecture diagrams
    When they click the remove button on the second diagram
    Then only 2 thumbnails should remain
    And the removed file should no longer be in the form data
 
  Scenario: Drag and drop file upload
    Given the architect is on step 5 "Uploads"
    When they drag a PNG file into the "Architecture Diagrams" drop zone
    Then the drop zone should highlight
    And when they drop the file a thumbnail preview should appear
 
  Scenario: Maximum file count is enforced
    Given the architect has uploaded 10 architecture diagrams
    When they try to add another file
    Then they should see "Maximum 10 files allowed"
    And the file input should be disabled

Suggested approach: Use input type="file" with react-hook-form and handle with FormData for the API. Use URL.createObjectURL for client-side previews. Validate type and size on the client before upload.


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

Decision: TypeScript with react-hook-form and zod. Form state lives in react-hook-form; no external state manager needed.

Feature: Type Safety and State Management
 
  Scenario: Form schema is defined with zod
    Given the developer creates the form schema
    Then each step should have its own zod schema
    And a combined schema should validate the full profile
    And TypeScript types should be inferred from the schema
 
  Scenario: Form state persists across steps
    Given the architect fills in step 1 and moves to step 3
    When they navigate back to step 1
    Then all fields should retain their values
    And no external state store should be required
 
  Scenario: Type errors are caught at compile time
    Given the developer passes incorrect field types
    Then the TypeScript compiler should report an error
    And the build should fail before runtime

Suggested approach: TypeScript with react-hook-form and zod is the strongly recommended default. TypeScript catches errors early and zod provides runtime validation that matches compile-time types.


10. Any tech stack constraints or preferred libraries?

Decision: Next.js 15 with App Router, TypeScript, react-hook-form, zod, shadcn/ui, and Tailwind CSS v4.

Feature: Tech Stack Integration
 
  Scenario: Form works with App Router server actions
    Given the form component is a Client Component
    When the architect submits the form
    Then data should be processed by a Server Action
    And the page should not require a full reload
 
  Scenario: Form works without JavaScript (progressive enhancement)
    Given JavaScript is disabled in the browser
    When the architect submits the form
    Then the form should still submit via native HTML form submission
    And server-side validation should catch any errors
 
  Scenario: Form loads performantly
    Given the architect navigates to the profile form
    Then the initial bundle should not exceed 50KB gzipped for the form
    And code splitting should load step components lazily
    And the Largest Contentful Paint should be under 2.5 seconds

Suggested approach: 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.


Putting It All Together: The Full Gherkin Suite

Once all 10 decisions are made, the complete Gherkin feature files become the contract between stakeholders and developers:

features/
  profile-form/
    01-purpose.feature           # What the form does
    02-field-types.feature       # Input types and behavior
    03-multi-step.feature        # Navigation and progress
    04-validation.feature        # All validation rules
    05-submission.feature        # Submit flow and error handling
    06-ui-ux.feature             # Styling and interactions
    07-accessibility.feature     # WCAG compliance
    08-file-uploads.feature      # Upload behavior
    09-type-safety.feature       # TypeScript/schema guarantees
    10-tech-stack.feature        # Performance and integration

Running Gherkins as Automated Tests

These Gherkin scenarios translate directly into Playwright + cucumber tests:

// features/step-definitions/multi-step.steps.ts
import { Given, When, Then } from "@cucumber/cucumber";
import { expect } from "@playwright/test";
 
Given("the architect is on step {int} {string}", async function (step, name) {
  await this.page.goto("/profile/create");
  for (let i = 1; i < step; i++) {
    await fillStepWithValidData(this.page, i);
    await this.page.getByRole("button", { name: "Next" }).click();
  }
  await expect(this.page.getByText(`Step ${step} of 6`)).toBeVisible();
});
 
When("they click {string}", async function (buttonText) {
  await this.page.getByRole("button", { name: buttonText }).click();
});
 
Then("step {int} {string} should be active", async function (step, name) {
  await expect(this.page.getByRole("heading", { name })).toBeVisible();
  await expect(this.page.getByText(`Step ${step} of 6`)).toBeVisible();
});

Recipe

Quick-reference recipe card -- copy-paste ready.

# Template: Gherkin scenario for any form decision
 
Feature: [Decision Area] -- [Form Name]
 
  Background:
    Given the user is logged in
    And they navigate to "[form URL]"
 
  Scenario: Happy path -- [what should happen]
    Given [precondition]
    When [user action]
    Then [expected outcome]
 
  Scenario: Validation -- [what should be rejected]
    Given [precondition]
    When [invalid action]
    Then [error message or blocked behavior]
 
  Scenario: Edge case -- [boundary condition]
    Given [precondition]
    When [edge case action]
    Then [expected handling]

When to reach for this: Before writing any form component code. Run through the 10-question checklist with stakeholders, write the Gherkin scenarios, get sign-off, then implement.

Gotchas

  • Writing Gherkins after the code -- defeats the purpose. Write them first so stakeholders can review behavior before implementation begins.

  • Too much implementation detail in scenarios -- Gherkin should describe what happens, not how. Write Then they should see "Email is required" not Then the zod schema should return an error object with path email.

  • Skipping the Background block -- repeated Given steps bloat every scenario. Extract common preconditions into Background.

  • One giant feature file -- split by decision area (validation, navigation, uploads) so different team members can own different files.

  • Not mapping scenarios to test code -- Gherkins without automation become stale documentation. Use Playwright + Cucumber or similar to keep them executable.

Alternatives

AlternativeUse WhenDon't Use When
User Stories onlySimple forms with few stakeholdersComplex forms needing precise behavior specs
Acceptance criteria in Jira/LinearTeam prefers issue trackers over feature filesYou want executable specifications
Storybook interaction testsVisual testing is the priorityYou need stakeholder-readable specs
Plain Playwright testsDev team writes tests without stakeholder reviewBusiness and dev need a shared language