More Usable Forms – Controlling Scroll Position

I constantly look for ways to improve and refine the usability of my Web applications. In particular, I always try to find ways to make my forms better because, let’s face it: if you’re building Web applications, you’re going to build forms. Most likely, you’re going to build lots of forms.

Anybody who has observed an average user trying to complete a form or a series of forms knows that the experience is often frustrating. Take extra measures to improve the usability of your forms — even in minor ways –- and you can really boost the user friendliness of your application on the whole.

One technique that you can use to improve your forms’ usability is to preserve the page scroll after post-backs. You might like to use this functionality in a search page, for example, on which the user can sort the results by column. If you have at the top of the page a from that accepts search parameters, and you display the results below, it can be very annoying for users to have to scroll down the page past the parameters to the results each time they want to sort their results by a given column. Luckily, we can do something about this.

The Solution

In this tutorial, I’m going to show you how easily to maintain a page’s scroll position when a form page posts back to itself. Although I’ve coded the example here in ColdFusion, the technique can be easily ported to other languages.

There are really only two things you need to do in order to make this technique work. You’ll have to write some JavaScript to grab the current X and Y scroll coordinates of your page and put them in the form so that they’re submitted when you post back to the current page. Then, you’ll have to take those X and Y scroll coordinates and, through a combination of server and client-side scripting, set the scroll coordinates of the page once it reloads. Piece of cake!

The Form Code

I’m using a bare-bones form here so you can really focus clearly on the mechanics of how the process works, rather that creating a more complicated search page of the sort I mention above. Once you know how to get things working, you can easily adapt this example to your own needs and be as clever as you want to be.

<cfparam name="FORM.name" default="Testing"> 

<html>
<head>
  <title>Test</title>
</head>
<body>

<form name="Form1"  
  method="POST"  
  action="<cfoutput>#CGI.SCRIPT_NAME#</cfoutput>">

  <p>1</p> <p>2</p> <p>3</p> <p>4</p> <p>5</p>  
  <p>6</p> <p>7</p> <p>8</p> <p>9</p> <p>10</p>

  <hr width="2000">

  <nobr>
  Name: <input type="text" name="name" value="<cfoutput>#FORM.name#</cfoutput>">
  <input type="submit" value="Submit"></nobr>

  <hr width="2000">
   
  <p>11</p> <p>12</p> <p>13</p> <p>14</p> <p>15</p>  
  <p>16</p> <p>17</p> <p>18</p> <p>19</p> <p>20</p>

</form>

</body>
</html>

This form page doesn’t do anything special at the moment. It simply posts back to itself, passing the name parameter. I have coded the paragraphs and numbers so that we have scrollable content on the page, and so that we have a visual guide to help judge how far the page has scrolled vertically (note that this script will preserve both the vertical and horizontal scroll, though).

Tracking the Scroll

The first step is to add some JavaScript to get the X and Y scroll values and put them into the form. To do this, we’ll need to add two hidden inputs to our form along with a few lines of JavaScript that will grab the current scroll values when the form is submitted and pass them to the hidden inputs. The saveScrollCoordinates() function will look at browser support for document.all and use the correct references to grab the scroll values and update the form inputs accordingly. We’ll use the onSubmit() event handler in our form to call it in this example.

I have coded the hidden fields that store the scroll values as text fields in this example, so if you have quick eyes, you can watch how the values change before the form is submitted.

<cfparam name="FORM.name" default="Testing"> 

<html>
<head>
  <title>Test</title>
<script language=javascript>
function saveScrollCoordinates() {
  document.Form1.scrollx.value = (document.all)?document.body.scrollLeft:window.pageXOffset;
  document.Form1.scrolly.value = (document.all)?document.body.scrollTop:window.pageYOffset;
}
</script>
</head>
<body>

<form name="Form1"  
  method="POST"  
  onSubmit="saveScrollCoordinates()"  
  action="<cfoutput>#CGI.SCRIPT_NAME#</cfoutput>">

  <p>1</p> <p>2</p> <p>3</p> <p>4</p> <p>5</p>  
  <p>6</p> <p>7</p> <p>8</p> <p>9</p> <p>10</p>

  <hr width="2000">

  <nobr>
  Name: <input type="text" name="name" value="<cfoutput>#FORM.name#</cfoutput>">
<input type="text" name="scrollx" value="0">
  <input type="text" name="scrolly" value="0">
  <input type="submit" value="Submit"></nobr>

  <hr width="2000">
   
  <p>11</p> <p>12</p> <p>13</p> <p>14</p> <p>15</p>  
  <p>16</p> <p>17</p> <p>18</p> <p>19</p> <p>20</p>

</form>

</body>
</html>

The second step is to take those values that are passed with the form and to do something with them. For this, we’ll need to add a few lines of Javascript with just a touch of ColdFusion. First, we’ll insert two additional cfparam tags at the top of the page so we have some default scroll values to work with on each page load. Then, we’ll define the scrollToCoordinates() function to set the page scroll and call it when the page loads using the onLoad() event handler in the <body> tag.

<cfparam name="FORM.name" default="Testing"> 
<cfparam name="FORM.scrollx" default="0">
<cfparam name="FORM.scrolly" default="0">

<html>
<head>
  <title>Test</title>
<script language=javascript>
function scrollToCoordinates() {
  <cfoutput>
  window.scrollTo(#FORM.scrollx#, #FORM.scrolly#);
  </cfoutput>
}
function saveScrollCoordinates() {
  document.Form1.scrollx.value = (document.all)?document.body.scrollLeft:window.pageXOffset;
  document.Form1.scrolly.value = (document.all)?document.body.scrollTop:window.pageYOffset;
}
</script>
</head>
<body onload="javascript:scrollToCoordinates()">

<form name="Form1"  
  method="POST"  
  onSubmit="saveScrollCoordinates()"  
  action="<cfoutput>#CGI.SCRIPT_NAME#</cfoutput>">

  <p>1</p> <p>2</p> <p>3</p> <p>4</p> <p>5</p>  
  <p>6</p> <p>7</p> <p>8</p> <p>9</p> <p>10</p>

  <hr width="2000">

  <nobr>
  Name: <input type="text" name="name" value="<cfoutput>#FORM.name#</cfoutput>">
<input type="text" name="scrollx" value="0">
  <input type="text" name="scrolly" value="0">
  <input type="submit" value="Submit"></nobr>

  <hr width="2000">
   
  <p>11</p> <p>12</p> <p>13</p> <p>14</p> <p>15</p>  
  <p>16</p> <p>17</p> <p>18</p> <p>19</p> <p>20</p>

</form>

</body>
</html>

Here is the play-by-play breakdown that describes what happens when the user clicks the button to submit the form:

  1. The saveScrollCoordinates() function is executed by the form’s onSubmit() event handler.
  2. saveScrollCoordinates() updates the scrollx and scrolly hidden inputs with the appropriate values.
  3. The form posts back to the same page.
  4. The ColdFusion form parameters scrollx and scrolly set the scroll coordinates in the scrollToCoordinates() function.
  5. The onLoad() event handler in the <body> tag calls the scrollToCoordinates() function.
  6. The window’s scroll properties are adjusted according to the passed coordinates.

Test the form and you’ll notice that no matter where you scroll, when you submit the page, you end up in the same place at which you started both vertically and horizontally. To better test the horizontal scroll, resize your browser so that it’s very narrow, then submit the form. Your X and Y scroll are preserved automatically An alternative way to accomplish this uses href anchors, but doing so is not nearly as accurate or smooth.

Wrapping Up

What about the example I gave above, where we had a search page containing an input form and results that could be sorted by column? In this instance, you’re likely to be submitting the form and executing a bit of SQL with slightly different values whenever the user chooses to click a column heading to sort. If you’re updating some hidden inputs with the new sort column and sort direction it should be an easy task to add this feature to your page. You need only insert the additional hidden inputs into your form and incorporate the JavaScript presented here into your own JavaScript. Your sort links could use the onClick() event handler to update the hidden scroll values and resubmit your form.

What I’ve shown you is just a simple example of this technique. The code here has been tested using Internet Explorer 6 and Mozilla Firefox for Windows, and Safari on a Mac. Use the idea behind this technique as a starting point. Apply your own creativity and skills to add a more polished, intuitive feel to the forms you use in your applications.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

No Reader comments

Comments on this post are closed.