Skip to content

fix(website-builder-react): stack Grid columns via CSS media query - #5628

Merged
adrians5j merged 2 commits into
release/6.4.10from
claude/trace-breakpoint-init
Sep 2, 2026
Merged

fix(website-builder-react): stack Grid columns via CSS media query#5628
adrians5j merged 2 commits into
release/6.4.10from
claude/trace-breakpoint-init

Conversation

@adrians5j

@adrians5j adrians5j commented Sep 2, 2026

Copy link
Copy Markdown
Member

Problem

Grid column stacking is resolved in JS from the runtime viewport breakpoint (breakpoint === stackAtBreakpoint) and applied as inline styles.

On SSR the breakpoint is always desktop, so the served HTML renders columns side-by-side and only corrects once the client hydrates and re-resolves the breakpoint. That causes a layout flash — and stays broken entirely when the content subtree doesn't hydrate (e.g. content rendered via next/dynamic({ssr:true})), which is how this surfaced on an OpenNext/SSG frontend: a grid set to stack at mobile stayed 2-column at mobile width.

Fix

Emit stacking as a scoped CSS media query in the rendered HTML, so the browser applies it by the real viewport width — no JS, no hydration dependency, no flash.

  • Grid renders a scoped class wb-grid-<element.id> plus a <style> block:
    @media (max-width: <breakpoint-width>px) {
      .wb-grid-<id> { flex-direction: column !important; }
      .wb-grid-<id> > .wb-grid-col { flex: 0 0 100% !important; max-width: 100% !important; }
    }
  • The stack width is read from the theme's breakpoint definition (no hardcoded widths).
  • ContentSdk.init now populates viewportManager breakpoints on the server too (the resize listener stays client-only), so SSR has the real widths to generate the media query.
  • CSS/class string building lives in gridStyles.ts (createGridClass, createGridStackingCss), not inline in the component.

Scope

Grid stacking only. Multiple grids and nested grids are safe (unique per-id class + direct-child combinator). Deliberately out of scope, as follow-ups:

  • Per-breakpoint styles for all elements (e.g. responsive rowGap/columnGap, spacing, visibility) — same JS→@media treatment, generalized.
  • Per-breakpoint content (text/RTE per breakpoint) and responsive images (<picture>/srcset).
  • The content-hydration gap and SSG draftMode behavior (orthogonal bugs).

Testing

  • Verified the @media block is present in the SSR HTML and the browser stacks columns at the breakpoint width with no client JS (content subtree not hydrated).
  • Verified in the editor — device preview stacking behaves correctly.
  • Builds clean; changed files formatted (oxfmt) and linted (oxlint).

Known follow-ups before merge

  • No unit tests yet for createGridClass / createGridStackingCss.
  • Changelog entry pending.

🤖 Generated with Claude Code

Grid column stacking was resolved in JS from the runtime viewport
breakpoint (`breakpoint === stackAtBreakpoint`) and applied as inline
styles. On SSR the breakpoint is always "desktop", so the served HTML
renders columns side-by-side and only corrects once the client
hydrates and re-resolves the breakpoint — causing a layout flash, and
staying broken entirely when the content subtree does not hydrate.

Stacking is now emitted as a scoped CSS media query in the rendered
HTML, so the browser applies it by the real viewport width with no JS,
no hydration dependency, and no flash.

- Grid renders a scoped class (`wb-grid-<id>`) plus a `<style>` block
  with `@media (max-width: <breakpoint-width>) { ... }`.
- The stack width is read from the theme's breakpoint definition.
- ContentSdk now populates `viewportManager` breakpoints on the server
  too (the resize listener stays client-only), so SSR has the real
  widths to generate the media query.
- String/CSS building lives in `gridStyles.ts`, not the component.

Scope: Grid stacking only. Per-breakpoint styles/content for other
elements are follow-ups.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@adrians5j adrians5j added this to the 6.4.10 milestone Sep 2, 2026
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@adrians5j
adrians5j merged commit 563d202 into release/6.4.10 Sep 2, 2026
17 checks passed
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.

1 participant