disabled

Prevents interaction with form controls. Disabled elements are skipped by tab order, excluded from form submission, and grayed out by default.

Overview

The disabled attribute prevents all interaction with a form control. A disabled element cannot be focused, clicked, or edited. It is skipped by keyboard tab order and excluded from form submission data.

This is the strongest way to deactivate a form control. If you need the value to still submit with the form, use readonly instead.

Applies to: <input>, <select>, <textarea>, <button>, <fieldset>

Values

StateFocusableEditableSubmittedTab Order
disabledNoNoNoSkipped
readonlyYesNoYesIncluded
inertNoNoYes (if in form)Skipped
(normal)YesYesYesIncluded
<form class="stacked"> <label for="email">Email</label> <input type="email" id="email" value="user@example.com" disabled /> <label for="plan">Plan</label> <select id="plan" disabled> <option>Free</option> <option selected>Pro</option> </select> <button type="submit" disabled>Submit</button> </form>

Fieldset Cascade

Adding disabled to a <fieldset> disables every form control inside it, regardless of nesting depth. This is the cleanest way to disable an entire section of a form with a single attribute.

<form class="stacked"> <fieldset disabled> <legend>Billing Address</legend> <label for="street">Street</label> <input type="text" id="street" value="123 Main St" /> <label for="city">City</label> <input type="text" id="city" value="Portland" /> <label for="state">State</label> <select id="state"> <option selected>Oregon</option> </select> </fieldset> <button type="submit">Continue</button> </form>

The <legend> element inside a disabled fieldset remains interactive. Any form controls inside the <legend> are not disabled by the fieldset cascade. This is intentional — the legend is considered a label, not a form control.

Form Submission

Disabled controls are excluded from FormData entirely. Their name/value pairs are not sent to the server. This catches developers off guard when they disable a field to make it "read-only" and then wonder why the value is missing.

<form class="stacked"> <label for="username">Username</label> <input type="text" id="username" name="username" value="jdoe" disabled /> <label for="role">Role</label> <input type="text" id="role" name="role" value="Admin" /> <button type="submit">Save</button> </form> <!-- On submit, only "role=Admin" is sent. "username" is excluded. -->

If you need the value submitted but non-editable, use readonly or pair the disabled field with a <input type="hidden"> that carries the value.

Styling

Browsers apply a default dimmed appearance to disabled controls. Use the :disabled and :enabled pseudo-classes for custom styling.

/* Default browser styling dims disabled controls */ input:disabled, select:disabled, textarea:disabled, button:disabled { opacity: 0.5; cursor: not-allowed; } /* Style the enabled state explicitly */ button:enabled { cursor: pointer; } /* Target inputs within a disabled fieldset */ fieldset:disabled input { background: var(--color-surface-raised); border-color: var(--color-border); }

Disabling During Submission

A common pattern is disabling the submit button while an async request is in flight. This prevents double-submission.

const form = document.querySelector('#payment-form'); const submitBtn = form.querySelector('button[type="submit"]'); // Disable while processing form.addEventListener('submit', (e) => { e.preventDefault(); submitBtn.disabled = true; submitBtn.textContent = 'Processing...'; fetch('/api/pay', { method: 'POST', body: new FormData(form) }) .then(() => { submitBtn.textContent = 'Done'; }) .catch(() => { submitBtn.disabled = false; submitBtn.textContent = 'Retry'; }); });

Accessibility

  • Disabled controls are removed from the tab order and announced as "dimmed" or "unavailable" by screen readers.
  • Do not rely on the default opacity alone to communicate the disabled state — the contrast may be insufficient. Consider adding a text indicator (e.g., "Currently unavailable") near the control.
  • For content that should remain visible and readable but non-interactive, prefer inert or readonly over disabled, since disabled controls may be skipped entirely by assistive technology.

Limitations

  • disabled does not work on <a> elements. Links have no disabled state — use aria-disabled="true" with JavaScript to prevent navigation, or replace the link with a <span>.
  • disabled does not work on <div> or other non-form elements. Use inert for that.
  • Some CSS frameworks override :disabled styles with high-specificity selectors. Check your cascade if custom disabled styles are not applying.
  • The disabled attribute is a boolean attribute. Writing disabled="false" still disables the element — the attribute's presence alone activates it. Remove the attribute entirely to re-enable.

See Also