Skip to content

perf(website): server components, MotionConfig reducedMotion, static counters - #704

Merged
ajitpratap0 merged 2 commits into
mainfrom
perf/motion-server-components
Oct 14, 2026
Merged

ajitpratap0 merged 2 commits into
mainfrom
perf/motion-server-components

Conversation

@ajitpratap0

Copy link
Copy Markdown
Owner

Summary

  • Drop 'use client' from CompareContent and VscodeContent; BenchmarksContent is now a server component with only a small client RawDataToggle (CSS grid-template-rows: 0fr to 1fr, no motion).
  • CodeExamples: remove AnimatePresence mode="wait" (no exit overlap).
  • New client Providers (MotionConfig reducedMotion="user" + LazyMotion with async domAnimation) wired in the root layout; Navbar, SearchModal, ThemeToggle, Button, GlassCard, ScrollProgressBar, GitHubStarButton, CopyButton, Playground use m.
  • AnimatedCounter renders the final value directly (no reset-to-0, no client JS). It is currently unused.
  • CodeExamples keeps full motion because it uses layoutId.
  • CHANGELOG.md intentionally not edited.

First-load JS (gzip, sum of chunks referenced by prerendered HTML, before -> after): /compare 347,406 -> 324,218 (-23.2 KB); /vscode 347,311 -> 324,218; /benchmarks 348,725 -> 325,377; / 351,842 -> 358,341 (+6.5 KB, home needs full motion for layoutId plus lazy features).

Test Plan

  • npm run typecheck clean; npm run lint 0 errors (7 pre-existing warnings); npm run build passes
  • Verify in browser with OS reduced-motion on that no motion-driven animation runs
  • Raw data disclosure on /benchmarks opens/closes; Lighthouse CI

Breaking Changes

None.

Closes #647
Part of #634

🤖 Generated with Claude Code

https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

@vercel

vercel Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
gosqlx-website Ready Ready Preview Oct 14, 2026 5:43pm UTC

@ajitpratap0

Copy link
Copy Markdown
Owner Author

Addressed review feedback:

  • CodeExamples: first mount renders with initial={false} (animation only after the user switches tabs). Prerendered / no longer contains opacity:0; code sample is visible without JS.
  • Playground and CodeExamples: layoutId underlines replaced by CSS scale-x transitions, so domAnimation is sufficient and no component uses the full motion import any more (all use m).
  • Home first-load JS (sum of gzip of scripts referenced by prerendered index.html) is now ~329,066 B, below the 351,842 B baseline.
    Gates: typecheck, lint, build pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 25s —— View job


Review of PR #704: server components, MotionConfig, m components

I reviewed the diff only. I didn't run the build, typecheck or browser checks.

Overall: The change is sound and the approach is sensible. It moves static pages to server components, uses LazyMotion with m, and adds MotionConfig reducedMotion="user". The CSS-only RawDataToggle is a clear improvement. The points below are mostly about the PR description not matching the code, plus a few small things.

Description vs. code

  • The summary says "CodeExamples keeps full motion because it uses layoutId". The diff does the opposite. CodeExamples.tsx now imports only m, and the layoutId tab indicator is replaced with a CSS scale-x span. Playground.tsx makes the same change.
  • The "+6.5 KB on /" explanation ("home needs full motion for layoutId") is therefore stale. Nothing in the diff uses motion or layoutId any more. Please re-measure / and update the description. If home is still heavier, domAnimation plus the lazy chunk and the Providers client boundary are more likely causes.
  • The second commit message mentions dropping layoutId, so the description probably wasn't updated after it.

Behaviour changes to check

  1. Tab underline (CodeExamples.tsx, Playground.tsx): the old shared-layout underline slid between tabs. The new one scales out from the left on the new tab while the old one shrinks, so the visual is different. That's acceptable, but it's a design change the description should mention. The motion-reduce: guard is missing here. MotionConfig doesn't affect CSS transitions, so these tab underlines still animate under OS reduced-motion. Add motion-reduce:transition-none. RawDataToggle already has it.
  2. Code panel swap (CodeExamples.tsx:143): removing AnimatePresence is fine. key={active} with initial={switched ? … : false} keeps the SSR content visible. switched is never reset and the state is trivial, so it works.
  3. inert in RawDataToggle: {...(open ? {} : { inert: true })} is fine on React 19. On React 18 it either fails typecheck or warns about the boolean attribute, and the string form is required. You said typecheck is clean, so this is probably React 19. aria-hidden={!open} together with inert is redundant. inert alone already hides the content from assistive tech and the tab order.
  4. Hidden raw data stays in the DOM (collapsed with 0fr and opacity-0). That's fine for SEO and no-JS. Large tables just stay in the HTML.
  5. m components before features load: LazyMotion with async features means whileHover and similar gestures are inactive until the chunk arrives. That's harmless. AnimatePresence exits on m.* also depend on the features being loaded. Both are acceptable, but the strict-mode default is worth knowing about. Nobody has accidentally left a motion.* component under LazyMotion strict.

Cleanup

  • AnimatedCounter is now unused and trivial. Delete it rather than keep dead code. Neither 'use client' nor any hook is left in it.
  • ScrollProgressBar still imports useReducedMotion, which is now partly redundant with MotionConfig reducedMotion="user". It's harmless, though, because it also skips mounting the bar entirely.
  • Providers.tsx and motion-features.ts are fine. The .then(mod => mod.default) is the documented pattern.

Test plan

  • The two unchecked items are the important ones: reduced-motion verification and the raw-data toggle. Since tab underlines and the toggle are CSS-driven, include a check that they respect prefers-reduced-motion (see point 1).
  • There are no automated tests for these UI changes. If the website has Playwright or Lighthouse CI, a simple toggle aria-expanded check would be cheap.

Security

No concerns.
· branch perf/motion-server-components

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 23s —— View job


Review of PR #704: server components, MotionConfig, static counters

I read the full diff (git diff origin/main...HEAD). I did not run typecheck, lint or build, and I did not test in a browser. The review is from reading the code only.

The change is clean overall. Moving to m components with LazyMotion and MotionConfig reducedMotion="user" is the right approach. No motion.* imports remain in src, so the lazy feature bundle isn't defeated anywhere.

Issues and suggestions

  1. The PR description is stale.

    • It says "CodeExamples keeps full motion because it uses layoutId". The current code uses m and has no layoutId; the tab underline is now a CSS scale-x transition.
    • It says AnimatedCounter "is currently unused", but src/components/home/PerformanceSection.tsx:54 renders it. That component is a server component now, so the counter shows the final value immediately and no longer counts up. This looks intended, but say so in the description.
    • The / first-load JS figure (+6.5 KB) was probably measured before the second commit, so you may want to re-measure it.
  2. LazyMotion without strict.

    • Adding strict to <LazyMotion> makes any accidental motion.* import throw at runtime. That would protect the bundle savings from regressions. It's optional, and cheap to add.
  3. m components render without animation features until the async chunk loads.

    • whileHover and whileTap do nothing until then. The initial/animate entrances run once the chunk arrives. This is fine for hover and tap.
    • Check SearchModal and the mobile menu, which use initial → animate and exit animations under AnimatePresence. Opening them very early could cause a brief pop. This is minor.
  4. CodeExamples: key={active} with no exit animation.

    • The old mode="wait" exit is gone. The new switched flag skips the entrance on first render, which is good for SSR visibility.
    • Remounting on each key change is fine. renderCode output is static.
  5. RawDataToggle accessibility.

    • aria-hidden plus inert on the collapsed panel is correct.
    • inert: true spread into a div type-checks in React 19. Your typecheck passed, so it's OK.
    • aria-hidden={!open} is redundant with inert. It's harmless.
    • Animating grid-template-rows is supported in modern browsers. Older Safari falls back to an instant toggle, which is acceptable.
  6. Playground tab underline.

    • The layoutId slide is replaced by a per-tab scale-x transition. Every tab renders its own underline span. The visual behaviour differs slightly (grow from the left rather than slide), but it's fine.
    • Add motion-reduce:transition-none here and in CodeExamples for consistency with RawDataToggle. The CSS transitions do not respond to MotionConfig.
  7. ScrollProgressBar is redundant.

    • It still calls useReducedMotion() and returns null. MotionConfig would not hide it, so keep this check.
  8. Test plan items still unchecked.

    • The reduced-motion browser check and the /benchmarks raw-data toggle check are still open. Please complete them. The reduced-motion check matters because the MotionConfig and CSS paths differ.

Security and tests

  • I saw no security concerns. There is no new user input handling or dynamic HTML.
  • The website has no unit tests for these components, which matches the existing repo state. A Playwright or Lighthouse CI run covers it.

Overall this looks good to merge after the description fixes and the optional strict and motion-reduce tweaks.
· branch perf/motion-server-components

Ajit Pratap Singh and others added 2 commits October 14, 2026 23:11
…edMotion, static counters

Drop 'use client' from CompareContent and VscodeContent, split the benchmarks
disclosure into a client RawDataToggle using CSS grid-template-rows, remove
AnimatePresence mode=wait from CodeExamples, add a Providers component with
MotionConfig reducedMotion=user and LazyMotion, move shared components to m,
and render AnimatedCounter with its final value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9
… components

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9
@ajitpratap0
ajitpratap0 force-pushed the perf/motion-server-components branch from 219fb2a to 9f0d35b Compare October 14, 2026 17:42
@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 17s —— View job


Review of PR #704

I read the code on the branch. I did not run typecheck, lint, build or a browser test.

Overall: The change looks good. Providers wraps MotionConfig reducedMotion="user" and LazyMotion. No motion.* imports are left; motion-features.ts and motion-variants.ts only import domAnimation and types.

Should fix

  1. Missing motion-reduce on the tab underlines.
    • Files: src/components/home/CodeExamples.tsx:129 and src/components/playground/Playground.tsx:272.
    • MotionConfig doesn't affect CSS transitions. The scale-x-0 / scale-x-100 underlines will still animate under OS reduced-motion.
    • Add motion-reduce:transition-none, as RawDataToggle already does.
  2. PR description is stale.
    • It says CodeExamples keeps full motion because of layoutId. The code now uses m and CSS scale-x.
    • It says AnimatedCounter is unused. src/components/home/PerformanceSection.tsx:54 uses it, so the stat counters no longer count up. Mention that as a visible behaviour change.
    • The / first-load JS figure (+6.5 KB) is superseded by your later ~329 KB measurement. Update the description.
    • Mention that the tab underline now grows from the left instead of sliding.

Optional

  • Add strict to <LazyMotion> so any future motion.* import fails loudly and the bundle savings are protected.
  • aria-hidden={!open} in RawDataToggle is redundant with inert. It's harmless.
  • AnimatedCounter is now a trivial server component that renders the value. That's fine. Keep it, or inline it.
  • m components with async features: whileHover and whileTap are inactive until the chunk loads. Entrance and exit animations in SearchModal and the mobile menu might pop if opened very early. This is minor.
  • ScrollProgressBar should keep its useReducedMotion check, because it skips mounting the bar entirely.

Performance

Moving Compare, Vscode and Benchmarks to server components saves about 23 KB gzip, as the PR reports. The CSS grid-rows toggle is a good replacement for motion.

Security and tests

No security concerns. There are no automated tests for these UI changes. The two unchecked test-plan items still need doing: the reduced-motion check in a browser and the /benchmarks toggle. Check the CSS underlines and toggle under prefers-reduced-motion as well.

Fix 1 and the description update, and this is good to merge.
· branch perf/motion-server-components

@ajitpratap0
ajitpratap0 merged commit 4edb971 into main Oct 14, 2026
30 checks passed
@ajitpratap0
ajitpratap0 deleted the perf/motion-server-components branch October 14, 2026 17:52

This branch was successfully deployed

1 active deployment
Preview — 9f0d35b5 Deployed Oct 14, 2026 by vercel[bot]
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.

perf(website): server components for static pages, MotionConfig reducedMotion, static counters [1.7]

1 participant