Problem
has no src/loading attribute (webjs-frame.js:53-59), so a region cannot self-load its content eagerly on connect or lazily on viewport entry. webjs has lazy COMPONENT module loading (static lazy=true, lazy-loader.js) but no lazy CONTENT loading for a region, forcing the fetch-in-handler anti-pattern AGENTS.md warns against for deferred content (comments, recommendations rail, expensive card). Compounding this, router-client.js:1192 sends x-webjs-frame on every frame fetch but no server file reads it: the server renders the full page (ssr.js:247-262) and the client discards all but the matched frame (router-client.js:1462-1469), so a frame pays full-page render+transfer cost for a region swap, the opposite of the X-Webjs-Have optimization webjs already ships.
Design / approach
Add native src/loading attributes to that fetch on connect or via the existing IntersectionObserver, and read the already-sent x-webjs-frame header in ssr.js to render only the requested subtree when isolable (full-page fallback). Reuses the native observer and the existing X-Webjs-Have-style header short-circuit.
Web-standards fit: Self-loading rides the native IntersectionObserver and a standard request header; the framework adds attribute handling and a render-scope branch, no new loader.
Prior art: Turbo frame_element.js observedAttributes src/loading, FrameLoadingStyle; frame_controller.js appearanceObserver vs #loadSourceURL.
Acceptance criteria
Filed from the production-readiness audit (webjs vs Next.js / Remix / Rails / Turbo / Lit). Theme: frames. Priority: P2. Kept to webjs identity: no-build, progressive enhancement, web-components-first, AI-first, batteries-included, close to web standards.
Problem
has no src/loading attribute (webjs-frame.js:53-59), so a region cannot self-load its content eagerly on connect or lazily on viewport entry. webjs has lazy COMPONENT module loading (static lazy=true, lazy-loader.js) but no lazy CONTENT loading for a region, forcing the fetch-in-handler anti-pattern AGENTS.md warns against for deferred content (comments, recommendations rail, expensive card). Compounding this, router-client.js:1192 sends x-webjs-frame on every frame fetch but no server file reads it: the server renders the full page (ssr.js:247-262) and the client discards all but the matched frame (router-client.js:1462-1469), so a frame pays full-page render+transfer cost for a region swap, the opposite of the X-Webjs-Have optimization webjs already ships.
Design / approach
Add native src/loading attributes to that fetch on connect or via the existing IntersectionObserver, and read the already-sent x-webjs-frame header in ssr.js to render only the requested subtree when isolable (full-page fallback). Reuses the native observer and the existing X-Webjs-Have-style header short-circuit.
Web-standards fit: Self-loading rides the native IntersectionObserver and a standard request header; the framework adds attribute handling and a render-scope branch, no new loader.
Prior art: Turbo frame_element.js observedAttributes src/loading, FrameLoadingStyle; frame_controller.js appearanceObserver vs #loadSourceURL.
Acceptance criteria
Filed from the production-readiness audit (webjs vs Next.js / Remix / Rails / Turbo / Lit). Theme: frames. Priority: P2. Kept to webjs identity: no-build, progressive enhancement, web-components-first, AI-first, batteries-included, close to web standards.