Tip Details Add a Related Tip

Rate as: Positive Negative

Scrolling HTML elements using the keyboard

The Problem
Javascript provides methods that allow you to scroll a window: scrollBy() and scrollTo(). But these methods are only available to the Window object; if you want to scroll an arbitrary document element such as a div, there is no direct way to do this in Javascript. By and large this isn't much of an issue. However, I did run into a problem where I actually needed to do this.

I was creating a widget for the Mac OS X dashboard (the tipstrs widget). In the widget, there is a single scrollable div much as the one seen on the tipstrs home page. The issue on the dashboard is that you can not grab the scroll bar and move it -- if you try to do this, it ends up moving the position of the widget itself. For most people this isn't an issue, you can still scroll the element using the scroll wheel on the mouse or the trackpad. But for folks without either of these options, they could not scroll.

The obvious solution to the problem is to provide keyboard shortcuts that result in the scrolling of the div element. But with Javascript unable to scroll an arbitrary element, I was kind of stuck.

The Solution
Happily, there is a solution to the problem. Javascript provides a method called scrollIntoView() which can be used on arbitrary elements in the document. With a slightly more complicated Javascript script, it is possible to use this method to provide scrolling of an arbitrary element in an HTML document. I'll describe the general solution first and then provide an example that you can run on your own machine.

The idea is to create a Javascript function that gets called when a key is pressed. In the Javascript function, you look to see if the key pressed indicates that scrolling is needed and, if it is, you scroll.

To achieve the scrolling, you divide the content in the element to be scrolled into blocks of content you can keep track of. When the request to scroll occurs, you can then loop through these blocks of content and call the scrollIntoView() method on them. You can keep repeating this until such time as you run out of elements, or until you actually effect the amount of scrolling in the element (using the scrollTop() method of the object to determine how much scrolling has taken place). It's actually pretty simple.

In the example code (shown below), there is one possible solution which makes use of this idea. There are a lot of other solutions available. The example shown works in Firefox, Safari, and IE7. I haven't tested in IE6 since I don't have, but if it doesn't work in IE6, I'm sure it could be made to work with some minor modifications.

The Example Code

Copy this code to a file on your computer and load the file into your browser, you'll then see this behavior in action...

<html>
<head>
    <title>Test using arrow keys to scroll a div element</title>
    
    <style type="text/css">
        div.scrollableDiv {
            overflow: auto;
            height: 300px;
            width: 400px;
            border: 1px solid black;
            padding: 3px;
        }
        
        div.caption {
            width: 400px;
            font-weight: bold;
            padding: 10px 3px;
        }
    </style>
    
    <script language="JavaScript" type="text/javascript">
        // Just use a global variable to keep track of our position in this example. Since
        // I only have one div element, I can use a single variable. If you wanted to make
        // multiple elements scrollable, you could use an array here, or elements in the 
        // document itself.
        var scrollLocation = 0;
        
        function checkForScroll(event, elementId, innerElementPrefix) {
             // Get a handle to the element which will be scrolled
            var el = document.getElementById(elementId);
            if ( !el ) {
                return;
            }
		
            // Get the current scroll offset.
            var currentScroll = innerEl.scrollTop;
            var latestScroll = currentScroll;
    
            // Get a handle to the element inside the scrolled element that is our current
            // scrolling target
            var innerEl = document.getElementById(innerElementPrefix + scrollLocation);
            
            // Check the event to see if they pressed a key we care about
            if ( event.which == 63233 ) {
                // They pressed the down arrow, we want to scroll down so long as we have
                // an element to work with up until the point where we actually move the 
                // scroll amount.
                while ( innerEl && currentScroll == latestScroll ) {
                    // Attempt to scroll
                    innerEl = document.getElementById(innerElementPrefix + (scrollLocation + 1));
                    if ( innerEl ) {
                        // There is such an element, move it into view and determine the new
                        // scroll amount for our element
                        scrollLocation++;
                        innerEl.scrollIntoView();
                        latestScroll = document.getElementById(elementId).scrollTop;
                    }
                }
            } else if ( event.which == 63232 ) {
                // They pressed the up arrow, we want to scroll up so long as we have
                // an element to work with up until the point where we actually move the 
                // scroll amount.
                while ( innerEl && currentScroll == latestScroll ) {
                    // Attempt to scroll
                    innerEl = document.getElementById(innerElementPrefix + (scrollLocation - 1));
                    if ( innerEl ) {
                        // There is such an element, move it into view and determine the new
                        // scroll amount for our element
                        scrollLocation--;
                        innerEl.scrollIntoView();
                        latestScroll = document.getElementById(elementId).scrollTop;
                    }
                }
            }
        }
    </script>
    
</head>

<body>
    <!-- The event is onKeyPress of this element... season to taste. -->
    <div class="scrollableDiv" id="divToScroll" onKeyPress="checkForScroll(event, 'divToScroll', 'scroll-')">
        <p id="scroll-0">You can scroll this div element by placing the mouse over it, clicking, and
        using the up and down arrow keys. This element does not have to be a div, it just is for
        this example.</p>
        
        <p id="scroll-1">For this example to work properly, each element in the div (this example
        using paragraph elements, but anything will work) must have an ID attribute associated with
        it where the ID attribute follows a pattern with an increasing number appended to the
        end.</p>
        
        <p>This paragraph has no ID attribute. Things still work, but the scrolling will skip this
        paragraph. That may not matter depending on your content and the size of the div being
        displayed. In this example, it is important that the numeric sequence not skip a value since
        it stops once it no longer finds an element. This need not be the case though, you could
        vary this behavior to suit your needs.</p>
        
        <p id="scroll-2">There are a lot of other ways that this example could be done. This is just
        one of the many was in which it can be made to work. You don't have to use a div, the event
        does not need to be just on the div, and you can use any type of block elements within the
        div to provide the scrolling.</p>
        
        <ul>
            <li id="scroll-3">I have now switched the elements in the div</li>
            <li id="scroll-4">and it still works</li>
            <li id="scroll-5">so long as the ID values maintain the same form.</li>
            <li id="scroll-6">Note that since this elements are not as &quot;tall&quot;</li>
            <li id="scroll-7">the scrolls take smaller steps</li>
            <li id="scroll-8">when going through these elements.</li>
        </ul>
        
        <p id="scroll-9">Mix and match as you wish</p>
        
        <p id="scroll-10">If you wanted to get really fancy, you could write a script to parse the
        DOM inside the target scroll element, and you could then scroll through the elements
        automatcially so that ID values are no longer needed. This may or may not result in the
        behavior you want based on the nature of your content.</p>
    </div>
    <div class="caption">Click on the scroll area above and then use the up and down arrow keys to
    scroll.</div>
</body>
</html>
Rating: 100% positive, 3 total Votes
Categories: javascript web programming HTML
Added: on Jun 22, 2007 at 9:34 am
Added By: rlansky

Comments on this Tip

Add a Comment
There are no comments for this tip
Your Comment:
(how to format)
Rate This Tip:

Verify Humanity:
Sorry, we know it's annoying, but please enter the characters shown in the image to the left so that we know you're an actual person and not an evil spammer. Thanks.
       

Related Tips

Telling when an iframe is done loading

100% positive, 0 comments
– Tip added by an anonymous user on Apr 18, 2008 at 8:05 am

Static variables in Javascript

100% positive, 2 comments - last added on May 08, 2008 at 4:19 pm
– Tip added by an anonymous user on Aug 03, 2007 at 4:19 pm

compressing javascript

100% positive, 0 comments
– Tip added by an anonymous user on Jun 12, 2008 at 3:02 pm

Creating vector graphics in javascript

100% positive, 0 comments
– Tip added by Marcos84 on May 10, 2007 at 2:44 pm

Don't use onChange events for checkboxes

Categories: HTML DOM javascript web
no ratings, 0 comments
– Tip added by an anonymous user on Oct 01, 2007 at 4:01 pm

Javascript variable naming

no ratings, 0 comments
– Tip added by an anonymous user on Sep 30, 2007 at 7:28 am

Code for creating Javascript CSS charts

no ratings, 0 comments
– Tip added by an anonymous user on Aug 21, 2007 at 12:23 pm

Efficient building of large strings in Javascript

no ratings, 0 comments
– Tip added by an anonymous user on Aug 08, 2007 at 12:52 pm

Avoid invalid title names when opening javascript windows

no ratings, 0 comments
– Tip added by an anonymous user on Aug 07, 2007 at 9:36 am

Nice article on javascript techniques

no ratings, 0 comments
– Tip added by rlansky on Apr 24, 2007 at 8:12 am

Using functions in conditionals in Smarty

Categories: php programming Smarty web
100% positive, 3 comments - last added on May 21, 2008 at 1:36 pm
– Tip added by rlansky on Aug 10, 2007 at 1:02 pm

Something to consider before switching platforms

100% positive, 0 comments
– Tip added by an anonymous user on Sep 25, 2007 at 7:31 pm

Trimming whitespace in Javascript

Categories: javascript programming
100% positive, 0 comments
– Tip added by an anonymous user on Sep 13, 2007 at 1:54 pm

Javascript Error: unterminated regular expression literal

100% positive, 0 comments
– Tip added by marty on Jun 26, 2008 at 1:20 pm

Copyright date on sites

Categories: web programming php Smarty
100% positive, 0 comments
– Tip added by an anonymous user on Mar 11, 2008 at 8:14 am

Wrap web text to any shape

100% positive, 0 comments
– Tip added by an anonymous user on Dec 16, 2007 at 10:35 am

Avoiding facebook timeout errors

Categories: Facebook programming web
100% positive, 0 comments
– Tip added by an anonymous user on Aug 21, 2007 at 5:21 pm

Declaring variables in Javascript

Categories: javascript web
100% positive, 1 comment - last added on Aug 17, 2007 at 8:08 am
– Tip added by an anonymous user on Aug 16, 2007 at 9:54 am

Javascript: How to Create a Random Number

0% positive, 0 comments
– Tip added by Walkere on Feb 23, 2008 at 9:49 pm

List HTML character entities

no ratings, 0 comments
– Tip added by an anonymous user on Sep 02, 2007 at 8:08 pm