How to “disable” pull-to-refresh on Salesforce mobile app with Lightning Components

If you’re here probably you’re having a headache on finding a way to disable the pull-to-refresh feature on Salesforce mobile app. Here, I will explain how you can circumvent it at all with a simple workaround.

Matteo Napolitano
Mar 29 · 5 min read

In the last few months, my team worked on a digitization project that leverages Salesforce mobile app in order to allow sales reps to do their job on the move.

Within the Lightning Experience, we’ve added a “Sales Wizard” feature built on top of a Lightning Flow and accessible by a Tab. Each step of the acquisition is made with a Flow Screen Element that encapsulates a Lightning Component.

If you’re unfamiliar with the usage of Lightning Component and Flow, please read more at https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/components_using_flow.htm

In this article it is supposed that you have some knowledge about Lightning Component Framework and the lifecycle of a Lightning Component.

It is possible that the content of the Screen, or well, the content of the Component, isn’t visible at all because the device visible area is not enough to contain it. This happens with a long text, with tables and also when some UI elements are in a position that is “reachable” only by scrolling the view.

Our application has some Lightning Components that contain forms with various fields to be filled out. The user needs to scroll the page to reach the fields that are at the bottom of the form and some useful action buttons are only reachable at the bottom of the view.

During development, we noticed the first difficulties with page scroll events, especially when the user activates the “pull-to-refresh” feature accidentally. This feature is certainly useful, but in our case it introduces a potential loss of information when data is entered but not yet saved. In addition, once the page is “refreshed”, the sales rep have to fill again the required form fields, thus it can be an experience that generate dissatisfaction also on customer side.

An example of what happens when user accidentally activates “pull-to-refresh”

So, we started looking around for a solution but, unfortunately, there isn’t a way to deactivate the “pull-to-refresh”. This feature is shipped within the mobile version of Salesforce and there are many reasons why it isn’t allowed to deactivate it.

For example, “pull-to-refresh” is useful when you need to refresh data or when you need to get new fields that were added to an object.

Then we thought about making a home-made solution! What about some old CSS trick and a pinch of JavaScript? What about two nested container with a fixed position in order to make scrollable the inner container?

Nested container with fixed position. The inner container is scrollable.

The image above shows an example of nested containers used to replicate a scrollable structure. Below you can see the code.

The mainContainer, bordered with red color, is used as a wrapper around the childContainer, bordered with a sea-green color. The magic is obtained with few CSS rules, as per the stylesheet below.

By now, you’ve obtained a scrollable container where you can put all the UI elements that you need. But it is not enough! In fact, if you test the Component obtained since here within the mobile version of Salesforce, you will experience that the “pull-to-refresh” is still working.

If you’ve ever investigated within the Aura Framework (the core of the Lightning Component Framework), probably you’ve faced with the component that handles the Scroll Events for the pages. This component is responsible for the handling of the touchmove event (read more about this event) when it is triggered over the page scroll wrapper.

We need to prevent the propagation of this event outside of the scope of our Component so we need to use the mainContainer as a “wall” for the event bubbling.

What is “Event Bubbling”? https://javascript.info/bubbling-and-capturing

Within the Renderer resource of our Component, we add an Event Listener on the mainContainer that handles the touchmove event by calling the scrollStopPropagation method declared within the Helper resource.

You’ve noticed that here we’ve used the addEventListener method with the useCapture parameter as true. But what does it mean?

In JavaScript, an Event Listener can be activated at the beginning of the event (“capture” phase) or at the end (“bubble” phase). Obviously, all the Event Listeners are activated by processing firstly the listener that use the Capture phase and than the listeners that use the Bubble phase.

Read more at: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

This way, we are blocking the event propagation after that the event is firstly captured.

Scroll event handled only by inner container. The “pull-to-refresh” feature is not activated.

In the Helper resource, we’ve declared the scrollStopPropagation method even if it simply executes a “stopPropagation” of the event. The method is declared outside of the callback scope of the addEventListener just for reusability, if you ever need to re-enable the “pull-to-refresh”.

In fact, you will be able to re-activate the feature by simply removing the Event Listener that you’ve just added.


There are some limitations that you must consider before adopt this solution in your Component.

  • If you’re using a Flow and you are encapsulating the Component within a Flow Screen Element, the Flow navigation buttons are not correctly positioned within the view.
  • If you need to handle the touchmove event for your own requirements (e.g.: hand drawing on a mobile device, sortable elements, etc..), you have to test the integration between the Event Listener explained above and your implementation.
  • It is not granted that this solution will work “as-is” also in future release of Salesforce.

All product names, logos, and brands are property of their respective owners. All company, product and service names used in this article are for identification purposes only.

Matteo Napolitano

Written by

Senior Digital Transformation Consultant @Deloitte