diff --git a/packages/fresh/src/runtime/client/partials.ts b/packages/fresh/src/runtime/client/partials.ts index bd5d3b5665b..31eb59c0fec 100644 --- a/packages/fresh/src/runtime/client/partials.ts +++ b/packages/fresh/src/runtime/client/partials.ts @@ -231,12 +231,21 @@ document.addEventListener("submit", async (e) => { return; } + const hasExplicitPartial = e.submitter?.hasAttribute(PARTIAL_ATTR) || + e.submitter?.hasAttribute("formaction") || + el.hasAttribute(PARTIAL_ATTR) || + el.hasAttribute("action"); + const rawPartialUrl = e.submitter?.getAttribute(PARTIAL_ATTR) ?? e.submitter?.getAttribute("formaction") ?? el.getAttribute(PARTIAL_ATTR) ?? el.action; const rawActionUrl = e.submitter?.getAttribute("formaction") ?? el.action; - if (rawPartialUrl !== "") { + // Only intercept forms that explicitly opt in to partial navigation + // via f-partial, formaction, or an explicit action attribute. Without + // this check, every form inside f-client-nav would be intercepted + // because el.action is always non-empty (defaults to the current URL). + if (hasExplicitPartial && rawPartialUrl !== "") { e.preventDefault(); const partialUrl = new URL(rawPartialUrl, location.href); diff --git a/packages/fresh/tests/partials_test.tsx b/packages/fresh/tests/partials_test.tsx index aae8420931f..03137f91deb 100644 --- a/packages/fresh/tests/partials_test.tsx +++ b/packages/fresh/tests/partials_test.tsx @@ -1857,6 +1857,49 @@ Deno.test({ }, }); +Deno.test({ + name: "partials - form without action inside f-client-nav not intercepted", + fn: async () => { + const app = testApp() + .post("/", (ctx) => { + return ctx.render( + +

form submitted normally

+
, + ); + }) + .get("/", (ctx) => { + return ctx.render( + +
+
+ + +

init

+
+ +
+
+
, + ); + }); + + await withBrowserApp(app, async (page, address) => { + await page.goto(address, { waitUntil: "load" }); + await page.locator(".init").wait(); + + // Form should do a full page navigation, not a partial update + await Promise.all([ + page.waitForNavigation(), + page.locator(".update").click(), + ]); + await page.locator(".submitted").wait(); + }); + }, +}); + Deno.test({ name: "partials - submit form redirect", fn: async () => {