Skip to content

fix(voting): return the proposal list to its scroll position on the way back from a proposal - #523

Closed
yhabib wants to merge 3 commits into
mainfrom
ux/proposal-list-scroll-restoration
Closed

yhabib wants to merge 3 commits into
mainfrom
ux/proposal-list-scroll-restoration

Conversation

@yhabib

@yhabib yhabib commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator

Motivation

Going back from a proposal to the list looked odd. The list reset to the top, and 300 ms later it animated a scroll to the proposals heading. The proposal the user had opened was no longer on screen, so they had to scroll to find their place again.

Changes

  • Replaced useScrollResetOnNavigation with useScrollRestoration, which keeps one scroll position of the main element per history entry and restores it on a history move back or forward.
  • Switched "Back to proposals" to a history move back when the list is the previous entry, so the list returns to where the user left it.
  • Added a fromProposalList history state flag on the list links for that check. A deep link or the command palette still pushes a new list entry at the top.
  • Changed the voting page to animate the scroll to the proposals only on a user toggle, not on mount.
  • Added unit tests for the hook.

The list reset to the top on the way back from a proposal and then
animated a scroll to the proposals heading. Now the main element keeps
one scroll position per history entry, "Back to proposals" moves back
in history when the list is the previous entry, and the voting page
only animates on a user toggle.
@yhabib
yhabib requested a review from a team as a code owner October 17, 2026 17:45
Copilot AI balanced review requested due to automatic review settings October 17, 2026 17:45
@zeropath-ai

zeropath-ai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

✅ No security or compliance issues detected. Reviewed everything up to 20b53c8.

Security Overview
Detected Code Changes
Change Type Relevant files
Refactor ► src/governance-app-frontend/src/common/hooks/useScrollResetOnNavigation.ts
    Deleted; replaced by new useScrollRestoration hook
Enhancement ► src/governance-app-frontend/src/common/hooks/useScrollRestoration.ts
    Add new scroll restoration hook to preserve scroll per history entry
► src/governance-app-frontend/src/common/hooks/useScrollRestoration.test.tsx
    Add tests for new hook functionality
Enhancement ► src/governance-app-frontend/src/common/utils/initializer.ts
    Extend typings with fromProposalList in HistoryState
Enhancement ► src/governance-app-frontend/src/routes/_auth.tsx
    Use useScrollRestoration instead of useScrollResetOnNavigation
Enhancement ► src/governance-app-frontend/src/routes/_auth/voting/index.tsx
    Add scrollTrigger logic to scroll proposals list on showProposals/proposalFilter changes
Enhancement ► src/governance-app-frontend/src/routes/_auth/voting/proposals/$id/index.tsx
    Add canBack/back handling integration with router and fromProposalList state

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

📊 Build Bundle Stats

The latest build generated the following assets:

dist/index.html                                           2.55 kB │ gzip:   0.87 kB
dist/assets/index-VUlzZ8kX.css                          137.47 kB │ gzip:  22.41 kB
dist/assets/icpLedger-Cq2nCtZu.js                         0.23 kB │ gzip:   0.21 kB
dist/assets/Skeleton-BKlrr9TJ.js                          0.44 kB │ gzip:   0.32 kB
dist/assets/useTvlValue-gUr4LQGE.js                       0.60 kB │ gzip:   0.41 kB
dist/assets/SensitiveValue-ZDtnCRFM.js                    0.61 kB │ gzip:   0.42 kB
dist/assets/PageHeader-Czh9Jiub.js                        0.77 kB │ gzip:   0.45 kB
dist/assets/CertifiedBadge-CkESh3Rm.js                    0.81 kB │ gzip:   0.48 kB
dist/assets/useGovernanceKnownNeurons-B91cJbfd.js         0.90 kB │ gzip:   0.58 kB
dist/assets/numbers-CghHMUee.js                           0.96 kB │ gzip:   0.52 kB
dist/assets/useIcpIndex-BNpJD6GN.js                       1.09 kB │ gzip:   0.64 kB
dist/assets/rolldown-runtime-CMxvf4Kt.js                  1.21 kB │ gzip:   0.67 kB
dist/assets/EmptyActionState-Cgw5Cos_.js                  1.61 kB │ gzip:   0.83 kB
dist/assets/AnimatedNumber-B6Oq6SOe.js                    1.96 kB │ gzip:   1.12 kB
dist/assets/useIcpIndexTransactionsPolling-CCOaYhOP.js    2.06 kB │ gzip:   1.11 kB
dist/assets/useGovernanceAppCanister-BT3HM9Ky.js          2.08 kB │ gzip:   1.01 kB
dist/assets/addressBook-CrnAp9B0.js                       2.14 kB │ gzip:   1.20 kB
dist/assets/advancedFeatures-CPKFmFY2.js                  2.29 kB │ gzip:   1.08 kB
dist/assets/ToggleGroup-BOIsY_VD.js                       4.71 kB │ gzip:   1.76 kB
dist/assets/tickers-qCIcFw_V.js                           6.05 kB │ gzip:   2.61 kB
dist/assets/QueryStates-CxEwYZQ7.js                       7.17 kB │ gzip:   2.64 kB
dist/assets/routes-Dbz731yi.js                            7.48 kB │ gzip:   2.49 kB
dist/assets/AlertDialog-CyR1HKhq.js                       7.80 kB │ gzip:   2.39 kB
dist/assets/TopicFollowingAccordion-Dy9grlD7.js           8.55 kB │ gzip:   3.42 kB
dist/assets/MutationDialog-Dcr7PRNB.js                    9.70 kB │ gzip:   3.54 kB
dist/assets/spamFilter-QWQu7P4J.js                       10.78 kB │ gzip:   4.70 kB
dist/assets/AmountInput-D0CSuUg6.js                      14.65 kB │ gzip:   5.99 kB
dist/assets/_id-Cmwlybg-.js                              14.91 kB │ gzip:   4.67 kB
dist/assets/_auth-BJosJN33.js                            19.69 kB │ gzip:   7.30 kB
dist/assets/GetTokens-DS-6P73h.js                        21.87 kB │ gzip:   8.19 kB
dist/assets/accounts-1eUrTAF7.js                         23.68 kB │ gzip:   8.27 kB
dist/assets/SendICPButton-QP36ANhG.js                    36.09 kB │ gzip:  13.22 kB
dist/assets/settings-BHK72Y9P.js                         40.29 kB │ gzip:  11.72 kB
dist/assets/dashboard-BkwDNZmr.js                        58.55 kB │ gzip:  18.09 kB
dist/assets/button-CU--YWgd.js                           62.59 kB │ gzip:  21.31 kB
dist/assets/voting-0Sx93GjO.js                           69.22 kB │ gzip:  21.66 kB
dist/assets/vendor-md-CgrKzPDI.js                        73.29 kB │ gzip:  19.98 kB
dist/assets/neurons-DtoVB_MO.js                          76.95 kB │ gzip:  23.23 kB
dist/assets/neuronDetail-D5pmXx2x.js                     87.09 kB │ gzip:  25.74 kB
dist/assets/index--Qthbnfc.js                           102.74 kB │ gzip:  29.56 kB
dist/assets/vendor-jsqr-CLmE8syL.js                     129.98 kB │ gzip:  47.50 kB
dist/assets/vendor-tanstack-BsMu5lpZ.js                 161.35 kB │ gzip:  49.40 kB
dist/assets/vendor-core-react-qLCIanUQ.js               189.81 kB │ gzip:  59.76 kB
dist/assets/vendor-recharts-Ydyhy8OZ.js                 280.27 kB │ gzip:  76.84 kB
dist/assets/vendor-icp-qGbRjjIG.js                      411.81 kB │ gzip: 104.30 kB
dist/assets/vendor-libs-DR16ufqG.js                     583.65 kB │ gzip: 188.18 kB

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Delayed list content can prevent restoration, and modified back-link clicks incorrectly navigate the current tab.

2 open issues
What changed in this PR

Preserves the voting list’s scroll position when returning from proposal details.

Changes:

  • Replaces scroll resets with history-entry restoration and unit tests.
  • Uses history navigation for proposals opened from the list.
  • Limits automatic scrolling to list visibility or filter changes.
File Description
src/​governance-app-frontend/​src/​routes/​_auth/​voting/​proposals/​$id/​index.tsx Adds history-aware back navigation.
src/​governance-app-frontend/​src/​routes/​_auth/​voting/​index.tsx Marks list links and avoids scrolling on mount.
src/​governance-app-frontend/​src/​routes/​_auth.tsx Enables the restoration hook.
src/​governance-app-frontend/​src/​common/​utils/​initializer.ts Types the list-origin history flag.
src/​governance-app-frontend/​src/​common/​hooks/​useScrollRestoration.ts Saves and restores scroll offsets.
src/​governance-app-frontend/​src/​common/​hooks/​useScrollRestoration.test.tsx Tests navigation and restoration behavior.
src/​governance-app-frontend/​src/​common/​hooks/​useScrollResetOnNavigation.ts Removes the reset-only hook.

Review effort: Balanced

…back link

If the list cache expired while the user read a proposal, the restore
ran against the loading skeleton and the browser clamped it. The
restore now retries as the content grows, until the position fits, the
user scrolls, or five seconds pass. A modified click on "Back to
proposals" follows the link as usual.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The app-wide restoration behavior needs browser-level validation of history navigation and delayed-content resizing beyond the mocked unit tests.

No open issues 🎉

2 resolved since last review

Review effort: Balanced

@yhabib

yhabib commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator Author

Checked in the browser against mainnet. Back from a proposal restores the list position in the same frame as the page swap. With the list cache removed, the restore first clamps to the skeleton and lands at the saved position once the list loads. A modified click on "Back to proposals" opens a new tab.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Automatic scroll clamping can incorrectly cancel restoration before the proposal list finishes loading.

1 open issue

Review effort: Balanced

…sition

Loading content can shrink and clamp the position again, so a changed
position is no sign of the user. The retry now stops on wheel, touch,
key, or pointer input instead.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approved

Static review identified no unresolved blocking issues; automated tests were not run.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@yhabib

yhabib commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #525.

@yhabib yhabib closed this Nov 6, 2026
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