- Update (July 17, 2018): Updated this script to remove IE8 support.
- Update (July 28, 2010): I have fixed a minor bug in this script to ensure compatibility with webforms2, part of a suite of scripts that implement cross-browser compatibility with the HTML5 forms specification.
I have been following the progression of the HTML5 Forms standard with great interest. It promises a whole slew of new visual and usability goodness to existing HTML forms (e.g. slider and calendar widgets), a client-side validation framework, and so much more. One of the things I was disappointed with, though, was that HTML5 cannot hide and show form elements depending on what the user has input into the form so far. To give a very simple example of what I am talking about, select a country of origin in the form below:
In HTML5, there is no way for a developer to tell the browser “only show me this block of HTML if country == 'Canada'
“. This is not a criticism of HTML5 or its authors — HTML5 forms has a lot of awesomeness in it (some of which I will blog about in my next article) and we can’t expect it to do everything. However, I have been using custom JavaScript to do this kind of stuff all the time, and wouldn’t it be great if the JavaScript challenged could do so? In the ideal world graphic designers, J2EE programmers with minimal front-end experience, and even my 75-year-old mom should be able to do this.
As a result, I present a JavaScript library, visibleIf
, which allows web developers to use HTML5 custom data attributes to define when blocks of HTML should be visible or invisible. Even if you are not a JavaScript genius, you will be able to make cool looking dynamic forms with very simple markup. For example, let’s take a look at the HTML of the example above:
<form> <table class="formTable"> <tr> <th>Country of Origin</th> <td><select name="country"> <option value=""> Select One... </option> <option value="Canada"> Canada </option> <option value="United States"> United States </option> </select> </td> </tr> <tr class="visibleIf" data-visibleif-rule="country == 'Canada'"> <th>Postal Code</th> <td><input type="text" name="postalCode" value="" /> </td> </tr> <tr class="visibleIf" data-visibleif-rule="country == 'United States'"> <th>Zip Code</th> <td><input type="text" name="zipCode" value="" /> </td> </tr> </table> </form>
This example is rather simple: the Postal Code form field is shown when country == 'Canada'
and Zip Code is shown when country == 'United States'
. Note that in order to hide and show a block of HTML, you must set two attributes inside the containing tag:
class="visibleIf"
: which lets the visibleIf.js script know that this block of HTML is to be hidden or shown according to thedata-visibleif-rule
data-visibleif-rule='rule expression'
: which contains the visibility rule. The rule variables are form element names, likecountry
is in the above example. You can do simple equality rules like this, or complex ones like:
<div class="visibleIf" data-visibleif-rule="country == 'Canada' && (city == 'Toronto' || city == 'Vancouver')"> ... </div>
If you know a little bit of JavaScript, you will note that you can use JavaScript functions to do interesting rules like:
<div class="visibleIf" data-visibleif-rule="parseInt(total) > 100"> ... </div>
Note that the above examples have visibleIf rules inside a tr
tag, they can be used in any tag inside an HTML form.
Although the above example is quite simple, you can use visibleIf to make really complex forms — you can even put visibleIf blocks inside of visibleIf blocks. To illustrate this I have created a more interesting form that shows what can be done using visibleIf.
See a more complex visibleIf form example
Hidden Fields – To Clear Or Not To Clear
If the user does something that hides some form fields (e.g. clicks on a checkbox) and then reverses that action (in this case clicking on the same checkbox), the fields will reappear with any previously filled-in data erased. Developers can override this default behavior by setting the class of the fields that shouldn’t be erased to visibleIf-doNotReset
. To illustrate this, I have created a page with two identical forms on it — one that erases the values inside hidden fields, and one that doesn’t. Play with the example and you’ll see what I mean.
See an example of a form with and without visibleIf-doNotReset
fields.
Hidden Fields – Submit To The Server, Or Not?
Also note that by default, only the visible form elements are submitted to the server (this is because when a form element is hidden by visibleIf
, its disabled
attribute is set to true
when the form is submitted). If developers wants to override this behavior, they can simply set the form’s class
to visibleIf-submitInvisibleData
.
See an example of a form with and without visibleIf-submitInvisibleData
class set.
The Quick “How-To” Guide”
Setting up your existing forms to use visibleIf is a quick, three-step process:
- Get the source from the visibleIf GitHub repo
- Include the visibleIf.css stylesheet and visibleIf.js JavaScript files into your web page:
<head> ... <link rel="stylesheet" href="/path/to/visibleIf.css" type="text/css" /> ... </head> <body> ... <!-- This should be as close the bottom of the body as possible --> <script type="text/javascript" src="/path/to/visibleIf.js"> </script> </body>
- Use the visibleIf rules as seen in the example above. Note that
&&
,||
and other logical operators are allowed in the expressions, as are JavaScript functions (e.g. parseInt, parseFloat, etc).
A Note On The Use Of Custom Data Attributes
Why did I bother with custom data attributes when making visibleIf
? Why did I just use the attribute data-visibleif-rule
instead of just visibleif-rule
or just rule
to place the visibility rule? Wouldn’t that be simpler?
data-
attributes are HTML compliant: . Their use ensure thatvisibleIf
will be compatible with future versions of HTML sincedata-
attributes are reserved to be used for JavaScript libraries. As long as you use the HTML5 DOCTYPE, your forms should also validate.- The
data-visibleif-
prefix will not collide with attributes used in other JavaScript libraries. There is a high chance thatdata-rule
could be used by another library. Using the name of the library in the attribute significantly reduces that possibility.
Download
Get the latest version of visibleIf.js
from the project’s GitHub page.
6 responses so far
1 Weston Ruter // Jun 21, 2010 at 12:21 am
Nice work! I really like your solution for declaratively writing dynamic forms that contextually change based on input.
Something else to consider is server-side validation. On the client the various inputs are shown and hidden to construct a model which must be validated in the client in order to submit to the server. But on the server, all of the data integrity checks have to be done as well or else anyone could POST anything if they disabled JavaScript for example. I took a stab at attacking this problem with my WordPress Forms plugin which basically implements HTML5 forms on the server: when a form is POSTed back to the server, output buffering is enabled and the form generated is loaded into a DOMDocument and is populated with the POST data received. Then the form elements are validated according to their HTML5 input types and misc validation constraints and only if these are all satisfied will the “success” action fire. Otherwise, the page returns with 400 Bad Response and the form is presented to the user already pre-populated with their previous entries along with the various invalid fields marked up with CSS classes that can be used to highlight which fields they got wrong.
All that to say, it would be awesome if your solution could be generalized into a server-side library which could enforce the same contextual visibility/validation.
By the way, I think I read somewhere that HTML5 data-* attributes should be all lower-case?
Great work as always!
2 zoltan // Jun 21, 2010 at 12:49 am
@Weston: Totally right about the data-* attributes being lower case. The post and the code has been updated accordingly. Thanks for the tip
Regarding a server-side library: it would be a great project to do. If only we didn’t have so many server-side languages … :-(
3 Weston Ruter // Jun 22, 2010 at 1:37 pm
Indeed, we need one server-side language to rule them all: JavaScript!
4 Sebastian Green // Jul 3, 2010 at 2:20 pm
Great lightweight solution.
5 hagai // Jul 3, 2010 at 2:21 pm
thank you for the trick!
Give Feedback
Don't be shy! Give feedback and join the discussion.
Please Note: If you are asking for help using the information on this page or if you are reporting a bug with the code featured here, please include a URL that shows the problem you are experiencing along with the browser/version number/operating system combination where the issue manifests itself. Without this information, I may not be able to respond.
denotes a required field.