Disable the form, not fields

One disabled fieldset locks every control while a form saves.

Sam Selikoff@samselikoff
Super easy way to add pending UI to a form: a disabled fieldset with a prefixed Tailwind class to target the pseudostate. <fieldset disabled className="disabled:opacity-70"> Watch the whole lesson on Build UI, free for the next three days!
Mar 20, 2023View on X ↗

1 · Save the profile

Press Save, then edit the name while it saves.

Only Save is disabledBad
<button disabled>Idle
Fieldset disabledGood
<fieldset disabled>Idle
<form action={save}>
  <fieldset disabled={pending} className="disabled:opacity-70">
    <input name="name" />
    <select name="plan" />
    <button>Save</button>
  </fieldset>
</form>

/* or plain CSS */
fieldset:disabled { opacity: .7; }

Why it matters, pros and cons

Why it matters

Disabling one button leaves every field editable, and a late response overwrites what you typed.

Pros

  • One attribute locks every input, select, checkbox and button inside it.
  • The :disabled pseudo-class styles the whole pending state from one selector.
  • No per-field disabled props to thread through components.

Cons

  • Disabled controls lose focus, so keyboard users land back on the page.
  • Disabled fields are left out of FormData, so read values before disabling.
  • For fast saves, optimistic UI avoids the lock altogether.