Skip to content

feat(grid): remember scroll position per view - #3646

Open
markov12 wants to merge 1 commit into
teableio:developfrom
markov12:feat/persist-grid-scroll-position-v2
Open

markov12 wants to merge 1 commit into
teableio:developfrom
markov12:feat/persist-grid-scroll-position-v2

Conversation

@markov12

Copy link
Copy Markdown

Problem

The grid always opens scrolled to the top-left. On wide tables, or tables where new rows are appended at the bottom, you have to scroll back to where you were every time you switch views, switch tables or reload the page.

Change

Remember each grid view's scroll position (vertical and horizontal) in localStorage, keyed by user + view, and restore it when the view is opened again. If the view was scrolled to the bottom, it stays pinned to the bottom after new rows are appended, so freshly added rows remain visible.

  • Grid gets an optional initialScrollState prop that seeds its scroll state on mount. GridViewBase already re-mounts the grid (via ViewSkeleton) on every view switch, so the restore is declarative and doesn't race the async layout with an imperative scrollTo.
  • InfiniteScroller aligns the DOM scrollbars with that initial offset once they are actually scrollable, and syncs the touch Scroller with the real position (on mount and at the start of each gesture) — otherwise its internal offset is stale and the first swipe jumps back to the top.
  • If the content no longer overflows (a resize, or a stale offset on a now-short view), the position snaps back to the top/left edge so the first rows/columns can't get stranded.
  • useGridScrollPosition (app) computes the initial state from storage and persists on scroll: debounced (500 ms), try/catch-guarded, and it ignores the transient zeros emitted while the grid lays out, so they can't overwrite the saved position.

Browser-only, no server or schema changes. Grid behaves exactly as before when initialScrollState isn't passed.

Testing

Manually tested on desktop and in Chrome device emulation (touch):

  • reload, switching tables / views and back — vertical and horizontal position restored
  • scrolled to the bottom / right edge, then switch away and back — stays at the bottom / edge
  • adding and deleting rows, resizing the window, collapsing / expanding the sidebar
  • touch: first swipe after coming back starts from the restored position

🤖 Generated with Claude Code

@CLAassistant

CLAassistant commented Sep 12, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


markov12 seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

Persist each grid view's vertical and horizontal scroll offset in localStorage
(keyed by user + view) and restore it when the view is reopened or the page is
reloaded. If the view was scrolled to the bottom, it stays pinned to the bottom
after new rows are appended.

The grid gets an `initialScrollState` prop that seeds its scroll state on
mount, so the restore doesn't race the async layout. InfiniteScroller aligns
the DOM scrollbars (and the touch scroller) with that initial offset once they
are scrollable, and snaps back to the top/left edge when the content no longer
overflows.
@markov12
markov12 force-pushed the feat/persist-grid-scroll-position-v2 branch from a69fbe2 to 585db14 Compare September 14, 2026 15:04
@markov12

Copy link
Copy Markdown
Author

Hi! Just a quick note that the CLA check is now passing. Is there anything else I should do on my side to move this forward? Happy to rebase or adjust the implementation if needed. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants