luke-chang / js-spatial-navigation

A javascript-based implementation of Spatial Navigation.
Mozilla Public License 2.0
370 stars 117 forks source link

Can the page be scrolled to the top/bottom if the there are no focusable items at the top/bottom? #55

Open ehbb opened 2 years ago

ehbb commented 2 years ago

I have a page with Some text as header and then some focusable button items in the rest of the page. Issue I'm facing is when I navigate (using keyboard keys and not mouse) through the page my Page doesn't scroll to the header part (because the header is not a focusable item).

I'm wondering whether is there a way I can scroll the page (through the Up key on keyboard) to the top (to the header) even if there's not focusable items on top of the page?

Here's some sample code (modified code of demo example 1.4_basic_config.html to have header and footer)

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>JavaScript SpatialNavigation Demo Page</title>

    <link rel="stylesheet" href="css/style_1.css">

    <script src="../spatial_navigation.js"></script>
    <script>
      window.addEventListener('load', function() {
        SpatialNavigation.init();

        // We can add some configurations when initializing a section.
        SpatialNavigation.add({
          selector: '.focusable',

          // Give it an id so we can identify it later.
          id: 'main',

          // Limit the navigating direction to vertical and horizontal only.
          // Targets in oblique (left-top, right-top, left-bottom, and
          // right-bottom) directions are always ignored.
          straightOnly: true,

          // This threshold is used to determine whether an element is
          // considered in straight (vertical or horizontal) directions. Valid
          // number is between 0 to 1.0. Setting it to 0.3 means an element is
          // counted in the straight directions if it overlaps the straight area
          // at least 0.3x of width of the area.
          straightOverlapThreshold: 0.5,

          // The previous focused element has high priority to be chosen as the
          // next candidate.
          rememberSource: true
        });

        SpatialNavigation.makeFocusable();
        SpatialNavigation.focus();

        [].slice.call(document.querySelectorAll('input[type="checkbox"]'))
          .forEach(function(elem) {
            elem.checked = true;

            elem.addEventListener('change', function(evt) {
              var config = {};
              config[this.value] = this.checked;

              // You can change the configurations of the specified section at
              // runtime. If section id is omitted, the global configurations
              // will be changed.
              SpatialNavigation.set('main', config);
            });
          });
      });
    </script>
  </head>
  <body>
  <!-- <div class="focusable" tabindex="-1" style="background-color: black; width: 100%; height: 100px;"></div> -->
  <div style="background-color: black; width: 100%; height: 100px;"></div>
    <div id="container">
      <div class="leftbox">
        <div class="focusable"></div>
        <div class="focusable"></div>
        <div class="focusable"></div>
        <div class="focusable"></div>
        <div class="nonfocusable"></div>
      </div>
      <div class="rightbox">
        <div id="main" class="focusable"></div>
        <div class="bottombox">
          <div class="focusable"></div>
          <div class="focusable"></div>
          <div class="focusable"></div><br>
          <div class="focusable"></div>
          <div class="focusable"></div>
          <div class="focusable"></div>
        </div>
      </div>
    </div>
    <div id="sidebox" tabindex="-1">
      Config:
      <label><input type="checkbox" name="config" value="straightOnly"> straightOnly</label>
      <label><input type="checkbox" name="config" value="rememberSource"> rememberSource</label>
    </div>
    <div style="background-color: black; width: 100%; height: 100px;"></div>
  </body>
</html>

In the above code when navigated through top and bottom arrow keys you can notice that header/footer part (black line) is not visible as the scroll doesn't go to top/bottom of the page.

One workaround is to make the header / footer part div tag as focusable. But, there could be scenarios where this is not possible always (for ex. if top/bottom of the page is just an empty space). So I'm wondering whether there can be any other solution to emable the scroll (through up/down arrow keys) to go completely to top/bottom of the page when navigated through arrow keys.

cyan-2048 commented 1 year ago

when the element is focused use scrollIntoView https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView

it is supported by all modern browsers, you could also use this very nice ponyfill that works very well https://github.com/KoryNunn/scroll-into-view