My web app built in ODC has this very annoying issue on mobile devices. Whenever scrolling through a screen, at random points, the screen scrolls back up to (almost) the top. There is pretty much no correlation between when it happens.It happens on pretty much every screen.
This does not happen on Chrome emulator. Currently I have the latest version of OutSystemsUI installed (2.30.0).
Why does this happen?
Hi Bjorn,
This is most likely related to how the mobile browser handles the OutSystems scroll container rather than a specific screen.
Since it happens across screens, at random points, and only on real devices, I’d check:
The fact that it doesn’t reproduce in the Chrome emulator is also a strong indication of a real-device browser/WebView scrolling issue.
I’d first test with a completely static, long screen. If that still jumps to the top, then it’s worth investigating OutSystems UI/mobile browser behavior specifically.
Hi Janakiraman,
Thanks for the response. I have tried to get the issue a little bit more clear, so here are some more details.
Some more details of the behavior of the issue:
I have also built a test screen with a completely static, long list with dummy data, no aggregates or anything, as you suggested. The issue does not happen on that screen.
Is there anything else I can test out? Maybe using the debugger with my phone connected to the computer. I'm open to all suggestions.
Thanks for the additional details — they really help narrow this down.
The fact that it doesn't happen on a fully static screen but does happen on screens with aggregates or data actions is the key clue here. What you're experiencing is most likely a DOM layout shift triggered by data loading, which causes the mobile browser's scroll position to reset. Mobile WebViews (especially iOS Safari) are far more sensitive to this than desktop browsers or the Chrome emulator, which is why it doesn't reproduce there.
Here's what's likely happening and what I'd suggest trying:
1. Set all aggregates and data actions to "Fetch: At start"This ensures data is fully loaded before the user can scroll, preventing any mid-scroll layout recalculation.
2. Set a fixed minimum height on your list or table containersIf the container has no defined height before data loads, the layout shift is more severe. Stabilizing the container height reduces the chance of a scroll reset.
3. Check your Layout block for anything that changes size after loadEven a header, banner, or notification bar that resizes after the screen loads will shift everything below it and can trigger a scroll jump.
4. Avoid any "Refresh Data" that could fire while the user is actively on the screenEven a background refresh causes a re-render, which can reset scroll position on mobile.
5. Try replacing a List + Table combination with a plain Table Records widgetYour description — "scrolling fast", "scrolling down then slightly up", "always jumps to the same position" — suggests the scroll anchor point is being reset when the rendered content shifts. A plain Table Records bound directly to the aggregate, without a wrapping List, may behave more stably.
6. Use Chrome Remote Debugger with your phone connectedGo to chrome://inspect on your desktop, open the app on your Android device, and watch the Elements panel while scrolling. You'll be able to see exactly which element changes height at the moment the scroll jumps — that will pinpoint the root cause.
Hope this helps — let me know what you find!
Browsers do not provide a reliable event that explicitly indicates "entire browser closed". Therefore, the industry-standard approach is: Maintain a count of active tabs. When the count reaches zero, assume all application tabs are closed and clear the storage. More Robust Implementation Store a unique Tab ID in sessionStorage (which is tab-specific) and maintain a list of active tabs in localStorage.Maintain an array of active Tab IDs in localStorage. On tab close, remove the current Tab ID. If no IDs remain, clear all application data. This approach avoids issues caused by page refreshes and provides better tab tracking than a simple counter.In Reactive Web, localStorage is shared across all tabs, so a single tab close cannot be identified directly from localStorage alone. A common approach is to maintain an "active tab" registry using sessionStorage (tab-specific) and localStorage (shared). On application load, register the tab and store a unique Tab ID. On beforeunload, remove the Tab ID from the shared registry. If active tabs still exist, update the shared data as required. If no active tabs remain, treat it as the last application tab being closed and clear the localStorage. Since browsers do not expose a reliable "browser closed" event, tracking active tabs and clearing storage when the last tab exits is the recommended pattern for OutSystems Reactive applications.