-
Notifications
You must be signed in to change notification settings - Fork 952
fix(marketing): reduce CLS on mobile landing page #1053
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,17 @@ | ||
| "use client"; | ||
|
|
||
| import { MeshGradient } from "@superset/ui/mesh-gradient"; | ||
| import { motion } from "framer-motion"; | ||
| import dynamic from "next/dynamic"; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n apps/marketing/src/app/components/HeroSection/components/ProductDemo/ProductDemo.tsx | head -25Repository: superset-sh/superset Length of output: 1025 🌐 Web query:
💡 Result: Best practices for client‑only components in Next.js 15 using
|
||
| import { useState } from "react"; | ||
| import { type ActiveDemo, AppMockup } from "../AppMockup"; | ||
| import { SelectorPill } from "./components/SelectorPill"; | ||
| import { DEMO_OPTIONS } from "./constants"; | ||
|
|
||
| const MeshGradient = dynamic( | ||
| () => import("@superset/ui/mesh-gradient").then((mod) => mod.MeshGradient), | ||
| { ssr: false }, | ||
| ); | ||
|
|
||
| export function ProductDemo() { | ||
| const [activeOption, setActiveOption] = | ||
| useState<ActiveDemo>("Use Any Agents"); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
Next.js 15 next/dynamic ssr false client component CLS layout shift guidance💡 Result:
Using
next/dynamicwith{ ssr: false }in Next.js 15 (App Router)ssr: falseonly works in Client Components. If you try to usedynamic(..., { ssr: false })in a Server Component, Next.js will error—move the dynamic import into a Client Component wrapper and render that wrapper from your Server Component. [1]suspense: truewithssr: false. Withsuspense: true, React will try to resolve Suspense on the server and Next.js documents thatssr: falseis effectively ignored / invalid in that configuration. [2]Preventing CLS (layout shift) when the client-only component loads
When you render a client-only dynamic component, the initial HTML won’t contain it—so you must reserve space for whatever will appear after hydration:
next/dynamic, use theloadingoption to render a placeholder. [1]min-height, or useaspect-ratiofor responsive boxes so the page layout doesn’t jump when the component appears. [3]Minimal pattern (App Router)
Key idea: the placeholder (or wrapper) should occupy roughly the same dimensions as the final widget to avoid CLS. [3]
Sources: Next.js Lazy Loading guide (updated Oct 15, 2025) [1], Next.js error note on
suspenseusage withssr: false[2], web.dev CLS guidance on reserving space / placeholders / aspect-ratio [3].🏁 Script executed:
Repository: superset-sh/superset
Length of output: 221
🏁 Script executed:
Repository: superset-sh/superset
Length of output: 3340
Add
loadingplaceholder to prevent CLS when ShaderAnimation hydrates.ssr: falseis appropriate for this client-only component, but it lacks aloadingoption with a placeholder that reserves space during client-side hydration. Since ShaderAnimation renders at the top of the hero section, the layout will shift when it loads. Provide a placeholder matching the component's final dimensions:Suggested fix
🤖 Prompt for AI Agents