243

I have two pages with HTML forms. The first page has a submission form, and the second page has an acknowledgement form. The first form offers a choice of many controls, while the second page displays the data from the submission form again with a confirmation message. On this second form all fields must be static.

From what I can see, some form controls can be readonly and all can be disabled, the difference being that you can still tab to a readonly field.

Rather than doing this field by field is there any way to mark the whole form as readonly/disabled/static such that the user can't alter any of the controls?

0

16 Answers 16

484

Wrap the input fields and other stuff into a <fieldset> and give it the disabled="disabled" attribute.

Example (http://jsfiddle.net/7qGHN/):

<form>
    <fieldset disabled="disabled">
        <input type="text" name="something" placeholder="enter some text" />
        <select>
            <option value="0" disabled="disabled" selected="selected">select somethihng</option>
            <option value="1">woot</option>
            <option value="2">is</option>
            <option value="3">this</option>
        </select>
    </fieldset>
</form>

10
  • 3
    Note: This has the side effect of making "the form controls that are [the fieldsets] descendants, except descendants of its first optional <legend> element ... [not] receive any browsing events, like mouse clicks or focus-related ones" (developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset). So any js event listeners you may have defined on descendants may not function. Commented Sep 20, 2016 at 18:18
  • 7
    @EricFreese Only in disabled state, which is what you want in 99 % of cases.
    – Jan Kalfus
    Commented May 11, 2018 at 12:51
  • 3
    This works but Values for disabled form elements are not passed to the processor method. Commented Sep 23, 2019 at 3:00
  • 4
    Note, this doesn't send data when form is submitted, not really a readonly mode per say
    – Herz3h
    Commented Nov 20, 2020 at 11:34
  • 2
    not the correct answer. this doesn't make the form readonly, but disabled Commented Oct 11, 2021 at 17:10
26

Edit (Jan 5, 24):

👉 Use the inert attribute on the whole <form> container element

The inert attribute can be added to sections of content that should not be interactive. When an element is inert, it along with all of the element's descendants, including normally interactive elements such as links, buttons, and form controls are disabled because they cannot receive focus or be clicked.

Please ignore the below (unrecommended) method


Old answer:

Not all form elements can be set to readonly, for example:
  • checkboxes
  • radio boxes
  • file upload
  • ...more..

Then the reasonable solution would be to set all form elements' disabled attributes to true, since the OP did not state that the specific "locked" form should be sent to the server (which the disabled attribute does not allow).

Another solution, which is presented in the demo below, is to place a layer on top of the form element which will prevent any interaction with all the elements inside the form element, since that layer is set with a greater z-index value:

DEMO:

var form = document.forms[0], // form element to be "readonly"
    btn1 = document.querySelectorAll('button')[0],
    btn2 = document.querySelectorAll('button')[1]

btn1.addEventListener('click', lockForm)
btn2.addEventListener('click', lockFormByCSS)

function lockForm(){
  btn1.classList.toggle('on');
  [].slice.call( form.elements ).forEach(function(item){
      item.disabled = !item.disabled;
  });
}

function lockFormByCSS(){
  btn2.classList.toggle('on');
  form.classList.toggle('lock');
}
form{ position:relative; } 
form.lock::before{
  content:'';
  position:absolute;
  z-index:999;
  top:0;
  right:0;
  bottom:0;
  left:0;
}

button.on{ color:red; }
<button type='button'>Lock / Unlock Form</button>
<button type='button'>Lock / Unlock Form (with CSS)</button>
<br><br>
<form>
  <fieldset>
    <legend>Some Form</legend>
    <input placeholder='text input'>
    <br><br>
    <input type='file'>
    <br><br>
    <textarea placeholder='textarea'></textarea>
    <br><br>
    <label><input type='checkbox'>Checkbox</label>
    <br><br>
    <label><input type='radio' name='r'>option 1</label>
    <label><input type='radio' name='r' checked>option 2</label>
    <label><input type='radio' name='r'>option 3</label>
    <br><br>
    <select>
      <option>options 1</option>
      <option>options 2</option>
      <option selected>options 3</option>
    </select>
  </fieldset>
</form>

2
  • 5
    Please note that the CSS solution is incomplete as it does not prevent keyboard navigation.
    – Tanriol
    Commented Jul 20, 2020 at 22:53
  • You may actually be able to disable keyboard navigation by messing with evt.preventDefault() or possibly tabindex but it's still a clumsy solution that will mess with accessibility Commented Jan 4 at 22:35
15
<form inert>

This won't change the styling of the form but will stop all the inputs from being focusable and stop any buttons from being clickable.

4
  • 2
    This is a new one to me. Thanks. They just keep updating HTML. Looks like most major browsers support it
    – Mawg
    Commented Aug 26, 2022 at 20:57
  • 1
    This will make the form completely unaccessible and undetectable for assistive technologies. Commented Sep 9, 2022 at 11:57
  • Yes good point. Depends on the scenario, but in most cases it’s better for a screen reader to tell the user there is a disabled button than to tell them nothing. Commented Sep 9, 2022 at 16:00
  • Not supported by Firefox :(
    – Jerther
    Commented Dec 2, 2022 at 14:16
7

You can use this function to disable the form:

function disableForm(formID){
  $('#' + formID).children(':input').attr('disabled', 'disabled');
}

See the working demo here

Note that it uses jQuery.

1
  • +1 Thanks, but I can't use client side side solutions, see updated question (sorry, my bad)
    – Mawg
    Commented Aug 18, 2010 at 3:43
6

On the confirmation page, don't put the content in editable controls, just write them to the page.

4
  • 1
    This really is the sanest approach. Don't present an uneditable form to a user, or you'll end up being an entry in the "Least Astonishment" question.
    – kibibu
    Commented Aug 18, 2010 at 3:51
  • 1
    how? How can I display a checkbox and its check/not-checked condition, or a radio group with its selected item, etc?
    – Mawg
    Commented Aug 18, 2010 at 6:27
  • 1
    @Mawg maybe it would be an option to just list the 'selected' items, without checkboxes. Like on a pizza order confirmation: just list all the ingredients you selected.
    – marc82ch
    Commented Feb 20, 2015 at 12:53
  • In this case not, but thanks for a good piece of lateral thinking which might help others.
    – Mawg
    Commented Feb 20, 2015 at 12:57
6

This is an ideal solution for disabling all inputs, textareas, selects and buttons in a specified element.

For jQuery 1.6 and above:

// To fully disable elements
$('#myForm :input').prop('disabled', true); 

Or

// To make elements readonly
$('#myForm :input').prop('readonly', true); 

jQuery 1.5 and below:

$('#myForm :input').prop('disabled', 'disabled');

And

$('#myForm :input').prop('readonly', 'readonly');
1
  • also $('#myForm').on('focus',function(e){$(e.targetElement).blur();}).submit(function(e){e.preventDefault();return false;})
    – Wil
    Commented Oct 18, 2021 at 8:27
5

There is no built-in way that I know of to do this so you will need to come up with a custom solution depending on how complicated your form is. You should read this post:

Convert HTML forms to read-only (Update: broken post link, archived link)

EDIT: Based on your update, why are you so worried about having it read-only? You can do it via client-side but if not you will have to add the required tag to each control or convert the data and display it as raw text with no controls. If you are trying to make it read-only so that the next post will be unmodified then you have a problem because anyone can mess with the post to produce whatever they want so when you do in fact finally receive the data you better be checking it again to make sure it is valid.

6
  • +1 Thanks, but I can't use client side side solutions, see updated question (sorry, my bad)
    – Mawg
    Commented Aug 18, 2010 at 3:02
  • "Based on your update, why are you so worried about having it read only? You can do it via client-side" Sorry, but 1) I can't do it client side (not my choice) and 2) if it looks to the user like he is changing things that might confuse him.
    – Mawg
    Commented Aug 18, 2010 at 3:45
  • @mawg well if it is purely for visuals then, the only thing I can recommend is replace all the controls inline with their text equivalent or adding the readonly property to the controls. There is no silver bullet and I get a sense that is what you are looking for. Can you post a snippet of the code that you are allowed to modify? It would help to just get a basis for what you are working with.
    – Kelsey
    Commented Aug 18, 2010 at 4:50
  • +1 thanks for the suggestion. I never really noticed before, but I must have filled in 100s or 1,000s if forms & vaguely remember a readonly version of them, not just text. Maybe I should fill in a few more & observe :-)
    – Mawg
    Commented Aug 18, 2010 at 6:26
  • 3
    Surprise... 6 years later the link is not working anymore.
    – mwallisch
    Commented Sep 14, 2016 at 14:26
4

There's no fully compliant, official HTML way to do it, but a little javascript can go a long way. Another problem you'll run into is that disabled fields don't show up in the POST data

2
  • 4
    If you've already validated the data you need to save it server side anyway. Sending it back and forth to the client is a big ol' security hole. Even if you use css, js or html to freeze the fields you can edit 'm with firebug or by manually changing the next HTTP request Commented Aug 18, 2010 at 1:04
  • +1 Thanks, but I can't use client side side solutions, see updated question (sorry, my bad)
    – Mawg
    Commented Aug 18, 2010 at 3:01
1

Have all the form id's numbered and run a for loop in JS.

 for(id = 0; id<NUM_ELEMENTS; id++)
   document.getElementById(id).disabled = false; 
1
  • +1 Thanks, but I can't use client side side solutions, see updated question (sorry, my bad)
    – Mawg
    Commented Aug 18, 2010 at 3:01
1

A simple need : display non-editable form (that can become editable later on) with minimum code and headache.

If you can't use the 'disabled' attribut (as it erases the value's input at POST), and noticed that html attribut 'readonly' works only on textarea and some input(text, password, search, as far I've seen), and finally, if you don't want to bother with duplicating all your select, checkbox and radio with hidden input logics, you might find the following function or any of his inner logics to your liking :

addReadOnlyToFormElements = function (idElement) {
    
        // textarea an input of type (text password search) work with the html readonly
        $('#' + idElement + ' textarea, #' + idElement + ' input').prop('readonly',true);
    
        // but you still have to destroy their associated objects, as I.E, datepicker (in our old project, datepicker is appended to input where 'Date' is in name attribut, don't ask why)
        $('#' + idElement + ' input[name*="Date"]').datepicker('destroy');
    
        // html readonly don't work on input of type checkbox and radio, neither on select. So, a safe trick is to disable the non-selected items
        $('#' + idElement + ' input[type="checkbox"]:not(:checked), #' + idElement + ' input[type="radio"]:not(:checked)').prop('disabled',true); 
        $('#' + idElement + ' select>option:not([selected])').prop('disabled',true);
    
        // and, on the selected ones, to disable mouse/keyoard events and mimic readOnly appearance
        $('#' + idElement + ' input[type="checkbox"]:checked').prop('tabindex','-1').css('pointer-events','none').css('opacity','0.5');
        $('#' + idElement + ' input[type="radio"]:checked').css('opacity','0.5');
        $('#' + idElement + ' select').css('background-color','#eee');
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

And there's nothing easier than to remove these readonly

removeReadOnlyFromFormElements = function (idElement) {

    // just remove the html readonly on textarea and input
    $('#' + idElement + ' textarea, #' + idElement + ' input').prop('readonly',false);

    // and restore their Objects, as I.E, datepicker
    $('#' + idElement + ' input[name*="Date"]').datepicker();

    // Remove the disabled attribut on non-selected
    $('#' + idElement + ' input[type="checkbox"]:not(:checked), #' + idElement + ' input[type="radio"]:not(:checked)').prop('disabled',false); 
    $('#' + idElement + ' select>option:not([selected])').prop('disabled',false);

    // Restore mouse/keyboard events and remove readOnly appearance on selected ones
    $('#' + idElement + ' input[type="checkbox"]:checked').prop('tabindex','').css('pointer-events','').css('opacity','');
    $('#' + idElement + ' input[type="radio"]:checked').css('opacity','');
    $('#' + idElement + ' select').css('background-color','');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

1

Easiest way

$('#yourform .YOUR_CLASS_FOR_INPUTS').prop('readonly', true);
3
  • it is true, but this is just ax example you can change your second selector to any other for example $('#yourform .yourclass_for_inputs').prop('readonly', true); Commented Jan 24, 2019 at 3:59
  • Does not work on select fields
    – TV-C-1-5
    Commented Feb 24, 2022 at 3:19
  • The better approach would be $('#yourform :input')....
    – jlh
    Commented May 13, 2022 at 15:48
0

I'd rather use jQuery:

$('#'+formID).find(':input').attr('disabled', 'disabled');

find() would go much deeper till nth nested child than children(), which looks for immediate children only.

1
  • 1
    Thanks, I will upvote you for trying, since you are new. BUT, please note that I clearly asked for a server side only solution. At that time I only coded PHP and not yet JS. A friendly hint to read the question as some might actually downvote you for this :-( Welcome aboard :-)
    – Mawg
    Commented Sep 25, 2015 at 13:53
0

Another simple way that's supported by all browsers would be:

HTML:

<form class="disabled">
  <input type="text" name="name" />
  <input type="radio" name="gender" value="male">
  <input type="radio" name="gender" value="female">
  <input type="checkbox" name="vegetarian">
</form>

CSS:

.disabled {
  pointer-events: none;
  opacity: .4;
}

But be aware, that the tabbing still works with this approach and the elements with focus can still be manipulated by the user.

2
  • 1
    I wouldn't recommend this, it's only changing the visual appearance of the form and (as you also pointed out) you are still able to change field values and even submit the form only by keyboard navigation. From the accessibility perspective it's also not very good. People with screen readers won't see this form as disabled as it's semantically not disabled.
    – acme
    Commented Mar 8, 2021 at 14:10
  • I like this best. It does not have anything finicky about it. If you use disable - you stand chance of having the form fields data not being saved. If you use readonly - it is also buggy and does not work properly with drop lists. And this method also works on both 'form' and 'fieldset' which is more elegant and concise - rendering the complete form unchangeable. As well - with the CSS you have the choice to display the now unusable sections in the way that suits your interface design and style and visual cues best.
    – TV-C-1-5
    Commented Feb 24, 2022 at 3:47
0

You can use an opaque layer over the form:

  1. Put position: relative on the form
  2. Add the transparent blocking div as a child of this form with position: absolute and top, bottom, left, right equal to 0
-1

You add html invisible layer over the form. For instance

<div class="coverContainer">
<form></form>
</div>

and style:

.coverContainer{
    width: 100%;
    height: 100%;
    z-index: 100;
    background: rgba(0,0,0,0);
    position: absolute;
}

Ofcourse user can hide this layer in web browser.

-2

To make a whole fieldset disabled conditionally in angular you can do like this:

 <fieldset [attr.disabled]="isEditable ? null : 'disabled'">
2
  • no one is asking anything about 'angular'
    – TV-C-1-5
    Commented Apr 29, 2022 at 1:47
  • to be fair, if you understand html and js frameworks, you clearly see that they meant <fieldset disabled>. which is not incorrect. Commented Feb 8, 2023 at 9:40

Not the answer you're looking for? Browse other questions tagged or ask your own question.