readonly

Makes form controls non-editable while keeping them focusable and included in form submission. The polite alternative to disabled.

Overview

The readonly attribute makes a form control non-editable while keeping it focusable, tabbable, and included in form submission. The user can see the value, select and copy the text, and tab through it — but cannot change it.

Use readonly when a value must be submitted with the form but should not be modified by the user. Common examples: order IDs, calculated totals, server-assigned values, and confirmation screens.

Applies to: <input> (text-like types only), <textarea>

Values

AttributeFocusableEditableSubmittedWorks On
readonlyYesNoYesText inputs, textarea
disabledNoNoNoAll form controls

The key difference: readonly keeps the value in the form payload. disabled removes it entirely.

<form class="stacked"> <label for="order-id">Order ID</label> <input type="text" id="order-id" name="order_id" value="ORD-2025-00482" readonly /> <label for="notes">Notes</label> <textarea id="notes" name="notes" rows="3">Delivered to front door.</textarea> <label for="amount">Amount</label> <input type="number" id="amount" name="amount" value="149.99" readonly /> <button type="submit">Update Notes</button> </form>

Readonly vs Disabled

These two attributes look similar but behave very differently. Choosing the wrong one is a common source of bugs.

<!-- readonly: focusable, submitted, not editable --> <label for="ro-field">Readonly</label> <input type="text" id="ro-field" value="Submitted with form" readonly /> <!-- disabled: not focusable, NOT submitted, not editable --> <label for="dis-field">Disabled</label> <input type="text" id="dis-field" value="Excluded from form" disabled />
Behaviorreadonlydisabled
User can editNoNo
User can focus/tabYesNo
User can select/copy textYesVaries by browser
Value submitted with formYesNo
Constraint validation runsNoNo
Visual appearanceSubtle (your CSS)Grayed out

Form Submission

This is the primary reason to choose readonly over disabled. Readonly fields are included in FormData and submitted to the server.

const form = document.querySelector('form'); form.addEventListener('submit', (e) => { e.preventDefault(); const data = new FormData(form); // readonly fields ARE included: console.log(data.get('order_id')); // "ORD-2025-00482" // disabled fields are NOT included: // data.get('disabled_field') → null });

Elements That Ignore readonly

The readonly attribute only works on text-like inputs and <textarea>. It has no effect on:

  • <select> — the user can still change the selection
  • <input type="checkbox"> — the user can still toggle it
  • <input type="radio"> — the user can still change the selection
  • <input type="range"> — the slider is still draggable
  • <input type="color"> — the picker still opens
<!-- readonly does NOT work on these elements --> <label for="color">Color</label> <select id="color" readonly> <option>Red</option> <option selected>Blue</option> <option>Green</option> </select> <!-- The user CAN still change the selection! --> <!-- Workaround: use disabled + hidden input --> <label for="color-display">Color</label> <select id="color-display" disabled> <option selected>Blue</option> </select> <input type="hidden" name="color" value="Blue" />

For these elements, use disabled paired with a <input type="hidden"> to carry the value, or use JavaScript to prevent changes.

Styling

Use the :read-only and :read-write pseudo-classes to style readonly fields distinctly from editable ones.

/* Style readonly inputs differently from editable ones */ input:read-only, textarea:read-only { background: var(--color-surface-raised); border-color: var(--color-border); color: var(--color-text); cursor: default; } /* Editable fields get the normal interactive style */ input:read-write, textarea:read-write { background: var(--color-surface); border-color: var(--color-border); }

Note: The :read-only pseudo-class also matches elements that are not editable by nature (like <p> or <div>). For precise targeting, combine it with an element selector: input:read-only.

JavaScript API

The readOnly property (camelCase) reflects the attribute.

// Toggle readonly programmatically const field = document.querySelector('#order-id'); field.readOnly = true; // make readonly field.readOnly = false; // make editable // Check state if (field.readOnly) { console.log('Field is read-only'); }

Accessibility

  • Screen readers announce readonly fields as "read-only" or "not editable". The value is still read aloud.
  • Because readonly fields are focusable, keyboard users encounter them during tab navigation. This is usually the desired behavior — the user can review the value in context.
  • If a field is readonly because the user lacks permission, consider adding a visible explanation (e.g., "This field is managed by your administrator").

Limitations

  • readonly is a boolean attribute. Writing readonly="false" still makes the field readonly. Remove the attribute entirely to make it editable again.
  • Constraint validation is skipped for readonly fields. A readonly field with pattern or required will not trigger validation errors.
  • Users can still submit the form with modified values via devtools or by removing the attribute. Always validate on the server.
  • There is no :read-only support for <select> in any useful way, since the attribute itself has no effect on selects.

See Also

  • disabled — fully deactivates a control (no focus, no submission)
  • inert — makes visible content non-interactive
  • pattern — validation constraints (skipped on readonly fields)
  • <input> element reference
  • <textarea> element reference