Skip to content

feat(loading): reveal skeletons after a delay and keep card heights stable - #466

Open
yhabib wants to merge 2 commits into
mainfrom
ux/skeleton-reveal-delay
Open

yhabib wants to merge 2 commits into
mainfrom
ux/skeleton-reveal-delay

Conversation

@yhabib

@yhabib yhabib commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation

The anti flicker delay ran only inside QueryStates, so the inline skeletons flashed on every fast query. Some cards also hid data already in hand, or changed height when the skeleton left. Split from #447.

Changes

  • Moved the 120ms anti flicker delay into the .skeleton class, and removed useDelayedFlag and LOADING_INDICATOR_DELAY.
  • Marked skeleton bars aria-hidden, and added SkeletonScreen to announce "loading" once for a full loading region (the QueryStates fallback here, the route skeletons in feat(loading): add content-shaped skeletons for every route #467).
  • Fixed CapitalCard, IcpPriceCard, TotalStakedCard, DailyRewardsCard, and the account and stakes cards, so they keep their height and show data already in hand.
  • Turned off animate-pulse under prefers-reduced-motion.

Next #467

Move the 120ms anti flicker delay into the `.skeleton` class, so every
skeleton holds its space at once and reveals itself late. Remove
`useDelayedFlag` and `LOADING_INDICATOR_DELAY`.

Mark skeleton bars `aria-hidden` and add `SkeletonScreen`, which
announces one "loading" for each region. Stop `animate-pulse` under
`prefers-reduced-motion`.

Fix the card skeletons that hid data already in hand or changed the
card height when they left.
Copilot AI balanced review requested due to automatic review settings October 1, 2026 06:51
@yhabib
yhabib requested a review from a team as a code owner October 1, 2026 06:51
@zeropath-ai

zeropath-ai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

✅ No security or compliance issues detected. Reviewed everything up to 0ccff63.

Security Overview
Detected Code Changes
Change Type Relevant files
Enhancement ► src/governance-app-frontend/src/app/styles/main.css
       Add skeleton CSS variables and animations for skeleton loading indicators
► src/governance-app-frontend/src/common/components/QueryStates.tsx
       Render SkeletonScreen/SkeletonText when loading instead of simple placeholders
► src/governance-app-frontend/src/common/components/Skeleton.tsx
       Update Skeleton to use new skeleton class and remove direct animation classes
► src/governance-app-frontend/src/common/components/skeletons/SkeletonScreen.tsx
       Add SkeletonScreen component to announce loading regions to SRs
► src/governance-app-frontend/src/common/components/skeletons/SkeletonText.tsx
       Add SkeletonText component to render multiple skeleton lines
► src/governance-app-frontend/src/common/constants/extra.ts
       Remove LOADING_INDICATOR_DELAY constant (loading indicator delay logic moved to skeletons)
► src/governance-app-frontend/src/common/hooks/useDelayedFlag.ts
(Deleted) Removal of delayed loading flag hook (relying on new skeleton approach)
Bug Fix ► src/governance-app-frontend/src/features/dashboard/components/IcpPriceCard.tsx
       Preserve card height when skeleton is shown by wrapping with min-height container and adjusting loading skeletons
► src/governance-app-frontend/src/features/dashboard/components/TotalStakedCard.tsx
       Use isTvlLoading/isMetricsLoading to show skeletons, ensure layout stability
► src/governance-app-frontend/src/features/stakes/components/summaryCards/CapitalCard.tsx
       Show USD line with skeleton only when ticker data is loading, move total staked display to always render
► src/governance-app-frontend/src/features/stakes/components/summaryCards/EarningsCard.tsx
       Adjust skeleton height from 4 to 5 for consistency
► src/governance-app-frontend/src/features/stakes/components/summaryCards/EngagementCard.tsx
       Adjust skeleton heights to better fit content and responsiveness
► src/governance-app-frontend/src/features/account/components/AccountCard.tsx
       Adjust loading skeleton height from 4 to 5 units
► src/governance-app-frontend/src/features/accounts/components/AccountsCard.tsx
       Adjust multiple skeleton instances to new sizing (h-5, w-...)
► src/governance-app-frontend/src/features/accounts/components/AccountsListItem.tsx
       Adjust balance skeleton height from 4 to 5 and width to 20
► src/governance-app-frontend/src/features/accounts/components/AccountsTotalCard.tsx
       Adjust skeleton heights from 4 to 5 and consistent widths
► src/governance-app-frontend/src/features/dashboard/components/DailyRewardsCard.tsx
       Wrap reward timestamp area in a div with min height and adjust skeleton height to 5
► src/governance-app-frontend/src/features/voting/components/FollowedNeuronCard.tsx
       Adjust known neurons loading skeleton width from 40 to 48
► src/governance-app-frontend/src/features/voting/components/FollowedNeuronCard.tsx
       Update conditional rendering to use new SkeletonWrapper for loading content

@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

📊 Build Bundle Stats

The latest build generated the following assets:

dist/index.html                                           2.47 kB │ gzip:   0.86 kB
dist/assets/index-SuMJuuY6.css                          133.03 kB │ gzip:  21.78 kB
dist/assets/address-DUWIBfGF.js                           0.19 kB │ gzip:   0.15 kB
dist/assets/externalServices-CK4eoRia.js                  0.19 kB │ gzip:   0.16 kB
dist/assets/icpLedger-dbKtrnb0.js                         0.23 kB │ gzip:   0.21 kB
dist/assets/Skeleton-BfjMGVwj.js                          0.43 kB │ gzip:   0.32 kB
dist/assets/useTvlValue-hq8hTqmg.js                       0.57 kB │ gzip:   0.39 kB
dist/assets/numbers-BK_F4UkU.js                           0.58 kB │ gzip:   0.36 kB
dist/assets/service-C3-pN7Yw.js                           0.59 kB │ gzip:   0.37 kB
dist/assets/Spinner-DXsuUYUj.js                           0.59 kB │ gzip:   0.41 kB
dist/assets/PageHeader-Czh9Jiub.js                        0.77 kB │ gzip:   0.45 kB
dist/assets/CertifiedBadge-Cfm8_SU1.js                    0.81 kB │ gzip:   0.48 kB
dist/assets/Separator-BKkeu7YW.js                         0.83 kB │ gzip:   0.49 kB
dist/assets/useIcpIndex-LSQ6k4FX.js                       1.07 kB │ gzip:   0.63 kB
dist/assets/rolldown-runtime-CMxvf4Kt.js                  1.21 kB │ gzip:   0.67 kB
dist/assets/EmptyActionState-DHVQH0cp.js                  1.61 kB │ gzip:   0.83 kB
dist/assets/addressBook-BVY3L6Md.js                       1.66 kB │ gzip:   0.99 kB
dist/assets/useGovernanceAppCanister-CvCNQfZ8.js          1.91 kB │ gzip:   0.96 kB
dist/assets/AnimatedNumber-Bt1Yi4kT.js                    1.96 kB │ gzip:   1.12 kB
dist/assets/useIcpIndexTransactionsPolling-B464jdn1.js    2.03 kB │ gzip:   1.10 kB
dist/assets/advancedFeatures-BekM2rj7.js                  2.29 kB │ gzip:   1.08 kB
dist/assets/ToggleGroup-Cj5hsx0e.js                       3.09 kB │ gzip:   1.41 kB
dist/assets/tickers-Dtwp5H32.js                           3.10 kB │ gzip:   1.48 kB
dist/assets/Switch-CwIMySih.js                            3.22 kB │ gzip:   1.44 kB
dist/assets/SensitiveValue-B_B997tI.js                    7.33 kB │ gzip:   3.29 kB
dist/assets/routes-BRoVSKc4.js                            7.46 kB │ gzip:   2.47 kB
dist/assets/spamFilter-CAcqWi9N.js                        8.54 kB │ gzip:   3.81 kB
dist/assets/badge-Y6nlKr54.js                             9.12 kB │ gzip:   2.75 kB
dist/assets/MutationDialog-z18BJWTZ.js                    9.51 kB │ gzip:   3.44 kB
dist/assets/events-DhmCPHxu.js                           10.38 kB │ gzip:   4.11 kB
dist/assets/_id-BJTep_-l.js                              14.33 kB │ gzip:   4.30 kB
dist/assets/_auth-C7riQCTy.js                            17.76 kB │ gzip:   6.54 kB
dist/assets/accounts-DsPaYnSf.js                         23.72 kB │ gzip:   8.19 kB
dist/assets/settings-C900f7jL.js                         42.05 kB │ gzip:  12.10 kB
dist/assets/GetTokens-C9c_id6G.js                        43.95 kB │ gzip:  16.02 kB
dist/assets/dashboard-DX1TO7JD.js                        50.49 kB │ gzip:  15.12 kB
dist/assets/button-BKAJJfrA.js                           58.36 kB │ gzip:  20.03 kB
dist/assets/neurons-CNBVUFx3.js                          68.08 kB │ gzip:  20.34 kB
dist/assets/voting-c2IZLqEV.js                           69.39 kB │ gzip:  21.32 kB
dist/assets/vendor-md-D9uF_eM9.js                        73.29 kB │ gzip:  19.98 kB
dist/assets/neuronDetail-Cfftfozr.js                     77.12 kB │ gzip:  22.92 kB
dist/assets/index-HtjdOyJ8.js                            80.39 kB │ gzip:  25.37 kB
dist/assets/vendor-jsqr-CLmE8syL.js                     129.98 kB │ gzip:  47.50 kB
dist/assets/vendor-tanstack-C1IVvUxz.js                 161.18 kB │ gzip:  49.35 kB
dist/assets/vendor-core-react-qLCIanUQ.js               189.81 kB │ gzip:  59.76 kB
dist/assets/vendor-recharts-D9ZdxDgm.js                 223.45 kB │ gzip:  64.01 kB
dist/assets/vendor-icp-CnZIDO_V.js                      411.60 kB │ gzip: 104.23 kB
dist/assets/vendor-libs-BUp5hYIb.js                     554.97 kB │ gzip: 181.04 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.

Copilot review overview

🟡 Changes recommended

TotalStakedCard still hides resolved values while an unrelated query remains loading.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Centralizes delayed skeleton rendering, improves loading accessibility, and stabilizes card layouts.

Changes:

  • Adds shared delayed skeleton styling with reduced-motion support.
  • Adds reusable skeleton text and accessible loading-region components.
  • Aligns card placeholders and preserves independently available data.
File Description
features/​voting/​components/​FollowedNeuronCard.tsx Adjusts placeholder width.
features/​stakes/​components/​summaryCards/​EngagementCard.tsx Stabilizes placeholder sizing.
features/​stakes/​components/​summaryCards/​EarningsCard.tsx Aligns forecast placeholder height.
features/​stakes/​components/​summaryCards/​CapitalCard.tsx Displays ICP total independently of price loading.
features/​stakes/​components/​StakedCard.tsx Aligns card placeholder heights.
features/​dashboard/​components/​TotalStakedCard.tsx Restructures value and percentage placeholders.
features/​dashboard/​components/​IcpPriceCard.tsx Reserves space for price-change content.
features/​dashboard/​components/​DailyRewardsCard.tsx Reserves space for reward-event content.
features/​accounts/​components/​AccountsTotalCard.tsx Aligns account summary placeholders.
features/​accounts/​components/​AccountsListItem.tsx Aligns balance placeholder height.
features/​accounts/​components/​AccountsCard.tsx Stabilizes account card placeholders.
features/​account/​components/​AccountCard.tsx Aligns USD placeholder height.
common/​hooks/​useDelayedFlag.ts Removes component-level loading delay.
common/​constants/​extra.ts Removes obsolete delay constant.
common/​components/​skeletons/​SkeletonText.tsx Adds reusable text-shaped skeletons.
common/​components/​skeletons/​SkeletonScreen.tsx Adds an accessible loading region.
common/​components/​Skeleton.tsx Applies centralized styling and accessibility semantics.
common/​components/​QueryStates.tsx Uses the new default skeleton screen.
app/​styles/​main.css Implements delayed reveal and reduced-motion behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/governance-app-frontend/src/features/dashboard/components/TotalStakedCard.tsx Outdated
Show the staked percentage as soon as the metrics load. Do not wait
for the ticker prices.

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.

Copilot review overview

🔵 Needs a closer look

Inline skeleton regions still lack the promised accessible loading announcement.

Review effort: Balanced
Findings: None

Resolved since last review (1)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Inline skeleton regions lack accessible loading announcements

src/​governance-app-frontend/​src/​common/​components/​Skeleton.tsx:20

Inline loading regions are still not announced. SkeletonScreen is only used by the default QueryStates fallback, while the many direct Skeleton callers—including the changed dashboard, account, and stake cards—remain unwrapped, so their loading state has no accessible status despite the new bars being explicitly hidden. Wrap each logical inline skeleton region in one SkeletonScreen (and also cover custom skeleton loadingComponent values) so screen readers receive the promised single loading announcement.

@yhabib

yhabib commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

I did not wrap the inline card skeletons in SkeletonScreen. The dashboard shows six or more at once, and each wrapper would announce "Loading" on its own. Before this PR the bars were empty divs, so screen readers skipped them already. The route skeletons in #467 give the one announcement for the page. I changed the PR body to match.

🤖 Addressed by Claude Code

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