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
| State | Focusable | Editable | Submitted | Tab Order |
|---|---|---|---|---|
disabled | No | No | No | Skipped |
readonly | Yes | No | Yes | Included |
inert | No | No | Yes (if in form) | Skipped |
| (normal) | Yes | Yes | Yes | Included |
<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 processingform.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
inertorreadonlyoverdisabled, since disabled controls may be skipped entirely by assistive technology.
Limitations
disableddoes not work on<a>elements. Links have no disabled state — usearia-disabled="true"with JavaScript to prevent navigation, or replace the link with a<span>.disableddoes not work on<div>or other non-form elements. Useinertfor that.- Some CSS frameworks override
:disabledstyles with high-specificity selectors. Check your cascade if custom disabled styles are not applying. - The
disabledattribute is a boolean attribute. Writingdisabled="false"still disables the element — the attribute's presence alone activates it. Remove the attribute entirely to re-enable.
See Also
readonly— non-editable but still focusable and submittedhidden/inert— hide or deactivate non-form content<fieldset>— group and disable controls together<button>element reference