Skip to story

Patterns Ux

Miller's Rule: Chunking Long Forms

8 min read · June 1, 2026 ★ Flagship

Reading level

The form that looked like homework

A checkout flow had 14 fields on one page: name, email, phone, address line 1, address line 2, city, state, zip, country, card number, expiry, CVV, billing address toggle, and a promo code. The design team had validated each field as necessary. Yet cart abandonment at checkout was 67%.

The same 14 fields, reorganized into 3 steps — Contact (3 fields), Shipping (6 fields), Payment (5 fields) — reduced abandonment to 41%. The work was identical. The perception of difficulty was completely different. Users could hold 3–5 fields in working memory at a time; 14 overloaded them before they'd filled in a single value.

Miller's Law (1956): working memory can hold approximately 7±2 items at once. The "magical number" is applied to form design as: the number of fields visible at one time should stay below 7. Modern research by Cowan (2001) suggests the actual capacity is closer to 4 items — the 7±2 figure is a useful upper bound, not an optimum.

The mechanism isn't just visual overwhelm — it's cognitive pre-commitment. When users see a long form, they estimate completion cost before starting. A 14-field form signals a high cost; users who are low-intent abandon before filling field 1. A 3-step form with 4 fields first signals a low entry cost — users start, and completion inertia carries them through.

When to chunk and how to do it

The 5-field threshold: If your form has more than 5 visible fields, consider chunking. The groupings should reflect natural semantic breaks, not arbitrary splits:

  • Identity chunk: name, email, phone — who you are
  • Location chunk: address, city, state, zip — where you are
  • Payment chunk: card details, billing — how you pay

Users understand these semantic groups intuitively. Splitting "address" across chunks (street in step 1, city/state in step 2) breaks the mental model and adds cognitive work.

// Multi-step form: show progress and validate on step advance
function CheckoutForm() {
  const [step, setStep] = useState(1);
  const totalSteps = 3;

  const advance = async () => {
    const valid = await validateCurrentStep(step);
    if (valid) setStep(s => s + 1);
    // Validate NOW, not on final submit — errors are cheapest to fix inline
  };

  return (
    <form>
      <ProgressBar current={step} total={totalSteps} />
      {step === 1 && <ContactFields />}
      {step === 2 && <ShippingFields />}
      {step === 3 && <PaymentFields />}
      <button onClick={advance}>
        {step < totalSteps ? 'Continue' : 'Place Order'}
      </button>
    </form>
  );
}

Validate each step before advancing — don't defer all validation to the final submit. Early errors are cheap; late errors are expensive.

Two patterns that compound with chunking:

  1. Smart defaults: auto-detect country from IP, pre-fill city/state from zip code, remember address from previous order. Each pre-filled field reduces cognitive load per step — a 6-field step with 3 pre-filled fields presents effective n=3.
  2. Progress anchoring: show "Step 2 of 3", not "67% complete". Concrete step counts reduce anxiety better than percentages because they imply a finite, manageable task. "2 of 3" says you're nearly done; "67%" implies mathematical work.

The completion inertia effect: users who complete step 1 of a 3-step form have a 78% completion rate for steps 2 and 3 combined. The hard part is getting them to start — chunking lowers the entry barrier.

The 15-field form that users abandoned before field 4

A B2B SaaS registration form had 15 fields: first name, last name, work email, company name, company size, industry, phone, job title, country, city, how did you hear about us, use case, number of team members, billing contact email, and a terms checkbox. Every field had been justified in a planning meeting. The form launched. Signups dropped 44% compared to the previous lighter form.

Session recordings showed the same pattern over and over: users would scroll the entire form before typing anything, pause, and then either start slowly or close the tab. The median field where users abandoned: field 4. They rarely even reached the middle of the form. The problem wasn't any individual field — it was the scroll to the bottom before starting.

The abandonment mechanism wasn't cognitive fatigue from filling fields — it was cognitive pre-commitment cost. Before entering a single character, users estimated the total effort of the form. A visible 15-field block signaled a high effort cost. Low-intent users — who had not yet decided to commit — weighed that cost and left. Miller's research on working memory capacity (7±2 items) is often cited as the cause, but the more direct mechanism here was the visual scope signal: users saw "15 fields of work" as a unit, not 15 individual simple tasks.

The form had a 23% overall completion rate but a 78% completion rate among users who reached field 6. The top-of-funnel loss was the entire problem. This is a common pattern in long-form data: the metric "form completion rate" averaged over all starts obscures that the form has two distinct populations — users who commit early and complete at high rates, and users who leave before starting. Chunking addresses the second population by reducing the perceived entry cost; it does almost nothing for the first population, who would have completed regardless.

Three steps, same 15 fields, 26-point conversion lift

The same 15 fields were reorganized into three steps: "About you" (name, work email, job title — 3 fields), "About your company" (company name, size, industry, country, city — 5 fields), and "Getting started" (use case, team size, billing email, how did you hear, terms — 5 fields + checkbox). A progress bar showed "Step 1 of 3."

Signups recovered to 69% above the broken form — 26 percentage points higher than the 15-field single-page version. Users didn't type more slowly or make fewer errors. They just didn't abandon before starting. The entry to step 1 went up 61% because the first thing users saw was three fields, not fifteen.

Implementation changes: each step was a separate React component rendered conditionally on a step state variable. Validation ran on "Continue" click for each step, not on final submit. This meant card errors surfaced at step 3, not in a 15-field error summary at the end. Step navigation preserved field values in a shared form state object — stepping back showed previously entered data. The progress bar used "Step 2 of 3" copy rather than a percentage, matching research showing concrete step counts reduce anxiety better than abstract percentages.

Post-launch measurement split three metrics: step-1 start rate (proxy for perceived entry cost), per-step completion rate (identifies which step has UX problems), and overall completion rate. Step-1 start rate improved 61%, confirming the chunking hypothesis. Step-2 completion was 91% — consistent with the "completion inertia" pattern, where users who finish step 1 are high-intent and self-selecting. The data also identified that step 3 had a 12% drop-off on the billing email field — a follow-up iteration that removed that field in favor of defaulting to the work email already captured in step 1.

Pattern at a glance

Annotated example: 15 fields single-page vs 3-step chunked form

❌ SINGLE PAGE — 15 FIELDS

First name
Last name
Work email
Company name
Company size
Industry ...
↓ 9 more fields below

Scroll preview signals high effort — users leave before field 1

✅ CHUNKED — STEP 1 OF 3

Step 1 of 3 — About you

First name
Work email
Job title

3 fields visible — low entry cost, high start rate

Try it: one page vs three steps

The "Single page" mode shows all fields at once. The "Chunked" mode shows 4–5 fields per step with a progress indicator. Start filling in both — notice when you feel the completion anxiety begin in the single-page version.

The demo measures time-to-first-field-interaction. The chunked form has a median time of ~800ms; the single-page form has a median time of ~2400ms. Users are deciding whether to start — and the long form gives them more reason to hesitate.

Notice the step-advance validation in the chunked version — errors surface on "Continue", not on final submit. Compare the error discovery experience: inline per-step errors vs a 14-field error summary at the bottom.

⚡ Interactive demo

Building chunked multi-step forms

The minimal pattern: conditional rendering on a step state variable, with fieldset/legend for semantic grouping within each step.

function MultiStepForm() {
  const [step, setStep] = React.useState(1);

  return (
    <form>
      <p>Step {step} of 3</p>

      {step === 1 && (
        <fieldset>
          <legend>About you</legend>
          {/* name, email, job title */}
        </fieldset>
      )}
      {step === 2 && (
        <fieldset>
          <legend>About your company</legend>
          {/* company fields */}
        </fieldset>
      )}
      {step === 3 && (
        <fieldset>
          <legend>Getting started</legend>
          {/* use case, team size, terms */}
        </fieldset>
      )}

      <button type="button" onClick={() => setStep(s => s + 1)}>
        {step < 3 ? 'Continue' : 'Submit'}
      </button>
    </form>
  );
}

Key pitfall: not validating before advancing. Always validate the current step's fields before calling setStep(s => s + 1). Deferring to final submit means errors surface after the user has already left the relevant step — recovery is expensive.

With React Hook Form, use a single useForm instance shared across steps. Trigger step-level validation with trigger(fieldsInCurrentStep) before advancing. Four implementation notes:

  1. Fieldset + legend is semantic grouping. It provides accessible group labeling for screen readers — use it even if you override the default fieldset border with CSS.
  2. Persist state on back navigation. Store all fields in the shared useForm register — data is preserved when users navigate back to a previous step without re-entering values.
  3. Progress: "Step N of M" beats percentages. Concrete step counts signal a finite task; percentages feel abstract and often underestimate remaining work.
  4. Keep steps semantically coherent. Don't split a related group (address line 1 in step 2, city/state in step 3) — chunking should match the user's mental model of what belongs together.
const { register, trigger, formState: { errors } } = useForm();
const STEP_FIELDS = {
  1: ['firstName', 'email', 'jobTitle'],
  2: ['company', 'companySize', 'industry'],
  3: ['useCase', 'teamSize', 'terms'],
};

const advance = async () => {
  const valid = await trigger(STEP_FIELDS[step]);
  if (valid) setStep(s => s + 1);
};

At design system scale, multi-step forms need a typed step schema: each step defines its fields, validation rules, and accessible legend. A <FormWizard steps={schema} /> component consumes the schema and handles step rendering, progress display, and per-step validation automatically. This prevents the common regression where a developer adds a field to a step array without adding its validation rules. For measurement, instrument three separate events: form_step_started, form_step_completed, and form_abandoned with a step property — this gives you per-step funnel data and pinpoints where users drop. Without per-step instrumentation, you can only see overall completion rate, which masks which step is the actual problem. Add a Storybook interaction test that steps through all steps and asserts the final submit fires correctly — this catches step-skip regressions that unit tests miss.

References

Remember

Key takeaways

  • If your form has more than 5–7 visible fields, split it into steps grouped by semantic theme. The work doesn't change; the perceived difficulty drops dramatically.
    Chunk semantically (who you are → where you are → how you pay), not arbitrarily. Users understand natural groupings; arbitrary splits add cognitive work rather than reducing it.
    Pre-fill and smart defaults compound with chunking — each auto-filled field reduces effective n per step. A 6-field step with 3 pre-filled fields presents effective n=3, well within working memory capacity.
  • Validate on step advance, not on final submit. Early errors are cheap; late errors destroy completion momentum.
    Use "Step 2 of 3" progress indicators rather than percentages. Concrete step counts are more reassuring than percentages because they imply a finite, manageable task.
    The completion inertia effect: users who complete step 1 finish at ~78% rate. The entry barrier is the primary abandonment point — chunking's main job is lowering the perceived cost of starting, not making the middle easier.

Enjoyed this case?

Case 3 of 4 in Patterns Ux · 28 of 31 live

Keep going

Finish this takeaway, then continue the track — Casey saved your spot locally.

Sign in with email to sync progress across devices (beta).

Inside the Casebook

New cases every few weeks — patterns from production UI engineering. Double opt-in, easy unsubscribe.

No spam. Unsubscribe anytime. Emails sent via Buttondown.

RSS feed
Casey, junior (idle)
Casey · Junior

Hey! I'm Casey — scroll through the case and I'll chime in with hints.