Skip to main content

Views ajax, Scroll to Top

and How to Disable It
Date
2018-07-16

In Drupal, when you use a View with AJAX, it automatically uses a scroll to top functionality. First, I find it annoying this functionality is not optional or configurable. Second, as far as I understand, it is not the best way to handle AJAXing content in in an accessible way. Theres a few other things that need to happen to be truly accessible. Ultimately, we just disable it on projects by default.

Here's how: Without getting into too many details here, for AJAXing, Drupal has specific commands it chains together for an AJAX response. For a simple view to update, the response contains 2 commands; replace command that replaces the view markup, and a scroll to top command that scrolls the browser to the top view element. In order to disable this we just remove that last command before the response is delivered in an Event Subscriber.

<?php

namespace Drupal\example_module\EventSubscriber;

use Drupal\views\Ajax\ViewAjaxResponse;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * Alter a Views Ajax Response.
 */
class ViewsAjaxResponseSubscriber implements EventSubscriberInterface {
  
  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    // We need to respond on the RESPONSE event.
    $events[] = ['onResponse'];
    return $events;
  }
  
  /**
   * Allows us to alter the Ajax response from a view.
   *
   * @param \Symfony\Component\HttpKernel\Event\ResponseEvent $event
   *   The event process.
   */
  public function onResponse(ResponseEvent $event) {
    $response = $event->getResponse();
    // Only act on a Views Ajax Responses.
    if ($response instanceof ViewAjaxResponse) {
      // Grab the list of comands.
      $commands = &$response->getCommands();
      // Remove the default scroll to top command.
      foreach ($commands as &$command) {
        if (isset($command['command']) && $command['command'] === 'viewsScrollTop') {
          unset($command['command']);
        }
      }
    }
  }
  
}

And in order for this event subscriber to take effect, you have to define it in your module's example_module.services.yml file, like so:

services:
  example_module.view_ajax_subscriber:
    class: Drupal\example_module\EventSubscriber\ViewsAjaxResponseSubscriber
    tags:
      - { name: event_subscriber }

Related Links:

Related Tech