diff --git a/.changeset/young-hornets-post.md b/.changeset/young-hornets-post.md
new file mode 100644
index 000000000000..514db808af45
--- /dev/null
+++ b/.changeset/young-hornets-post.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Fixes a bug where the "tap" prefetch strategy worked only on the first clicked link with view transitions enabled
diff --git a/packages/astro/e2e/fixtures/prefetch/src/components/ViewTransitionsLayout.astro b/packages/astro/e2e/fixtures/prefetch/src/components/ViewTransitionsLayout.astro
new file mode 100644
index 000000000000..ceb6f8cb0023
--- /dev/null
+++ b/packages/astro/e2e/fixtures/prefetch/src/components/ViewTransitionsLayout.astro
@@ -0,0 +1,14 @@
+---
+import { ClientRouter } from 'astro:transitions';
+---
+
+
+	
+		Testing
+		
+	
+	
+			
+	
+
+
diff --git a/packages/astro/e2e/fixtures/prefetch/src/pages/view-transitions/1.astro b/packages/astro/e2e/fixtures/prefetch/src/pages/view-transitions/1.astro
new file mode 100644
index 000000000000..aed64ab9c1d4
--- /dev/null
+++ b/packages/astro/e2e/fixtures/prefetch/src/pages/view-transitions/1.astro
@@ -0,0 +1,10 @@
+---
+import ViewTransitionsLayout from "../../components/ViewTransitionsLayout.astro";
+---
+
+
+View Transitions 1
+	
+	
+2
+
diff --git a/packages/astro/e2e/fixtures/prefetch/src/pages/view-transitions/2.astro b/packages/astro/e2e/fixtures/prefetch/src/pages/view-transitions/2.astro
new file mode 100644
index 000000000000..c9ffcc410cbf
--- /dev/null
+++ b/packages/astro/e2e/fixtures/prefetch/src/pages/view-transitions/2.astro
@@ -0,0 +1,7 @@
+---
+import ViewTransitionsLayout from "../../components/ViewTransitionsLayout.astro";
+---
+
+
+View Transitions 2
+
diff --git a/packages/astro/e2e/fixtures/prefetch/src/pages/view-transitions/index.astro b/packages/astro/e2e/fixtures/prefetch/src/pages/view-transitions/index.astro
new file mode 100644
index 000000000000..8ea5fd567ac1
--- /dev/null
+++ b/packages/astro/e2e/fixtures/prefetch/src/pages/view-transitions/index.astro
@@ -0,0 +1,8 @@
+---
+import ViewTransitionsLayout from "../../components/ViewTransitionsLayout.astro";
+---
+
+
+View Transitions index
+1
+
diff --git a/packages/astro/e2e/prefetch.test.js b/packages/astro/e2e/prefetch.test.js
index 2da44189a305..eb45aa5b8f97 100644
--- a/packages/astro/e2e/prefetch.test.js
+++ b/packages/astro/e2e/prefetch.test.js
@@ -56,6 +56,24 @@ async function expectUrlNotPrefetched(url, page) {
 	expect(reqUrls).not.toContainEqual(url);
 }
 
+/**
+ * @param {import('@playwright/test').Page} page
+ * @param {string} selector
+ */
+async function mouseDown(page, selector) {
+	const box = await page.locator(selector).boundingBox();
+	await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
+	await page.mouse.down();
+}
+
+/**
+ * @param {import('@playwright/test').Page} page
+ */
+async function waitForPageLoad(page) {
+	await page.waitForEvent('response');
+	await new Promise(res => setTimeout(res, 500)); // wait for transition to finish
+}
+
 test.describe('Prefetch (default)', () => {
 	let devServer;
 
@@ -393,3 +411,75 @@ test.describe('Prefetch (default), Experimental ({ clientPrerender: true })', ()
 		expect(await scriptIsInHead(page, 'prefetch-load')).toBeTruthy();
 	});
 });
+
+test.describe('Prefetch View Transitions', () => {
+	let devServer;
+
+	test.afterEach(async () => {
+		await devServer.stop();
+	});
+
+	test('"load" strategy', async ({ page, astro }) => {
+		devServer = await astro.startDevServer({
+			prefetch: {
+				defaultStrategy: 'load',
+			},
+		});
+		await page.goto(astro.resolveUrl('/view-transitions'));
+		await expectUrlPrefetched('/view-transitions/1', page);
+
+		await Promise.all([waitForPageLoad(page), page.click('a')]);
+		await expectUrlPrefetched('/view-transitions/2', page);
+	});
+
+	test('"viewport" strategy', async ({ page, astro }) => {
+		devServer = await astro.startDevServer({
+			prefetch: {
+				defaultStrategy: 'viewport',
+			},
+		});
+		await page.goto(astro.resolveUrl('/view-transitions'));
+		await expectUrlPrefetched('/view-transitions/1', page);
+
+		await Promise.all([waitForPageLoad(page), page.click('a')]);
+		await expectUrlPrefetched('/view-transitions/2', page);
+	});
+
+	test('"tap" strategy', async ({ page, astro }) => {
+		devServer = await astro.startDevServer({
+			prefetch: {
+				defaultStrategy: 'tap',
+			},
+		});
+		await page.goto(astro.resolveUrl('/view-transitions'));
+
+		await expectUrlNotPrefetched('/view-transitions/1', page);
+		await mouseDown(page, 'a');
+		await expectUrlPrefetched('/view-transitions/1', page);
+
+		await Promise.all([waitForPageLoad(page), page.mouse.up()]);
+
+		await expectUrlNotPrefetched('/view-transitions/2', page);
+		await mouseDown(page, 'a')
+		await expectUrlPrefetched('/view-transitions/2', page);
+	});
+
+	test('"hover" strategy', async ({ page, astro }) => {
+		devServer = await astro.startDevServer({
+			prefetch: {
+				defaultStrategy: 'hover',
+			},
+		});
+		await page.goto(astro.resolveUrl('/view-transitions'));
+
+		await expectUrlNotPrefetched('/view-transitions/1', page);
+		await page.locator('a').hover();
+		await expectUrlPrefetched('/view-transitions/1', page);
+
+		await Promise.all([waitForPageLoad(page), page.click('a')]);
+
+		await expectUrlNotPrefetched('/view-transitions/2', page);
+		await page.locator('a').hover();
+		await expectUrlPrefetched('/view-transitions/2', page);
+	});
+});
diff --git a/packages/astro/src/prefetch/index.ts b/packages/astro/src/prefetch/index.ts
index 34d3b5363998..2cfd84940385 100644
--- a/packages/astro/src/prefetch/index.ts
+++ b/packages/astro/src/prefetch/index.ts
@@ -54,7 +54,7 @@ export function init(defaultOpts?: InitOptions) {
  */
 function initTapStrategy() {
 	for (const event of ['touchstart', 'mousedown']) {
-		document.body.addEventListener(
+		document.addEventListener(
 			event,
 			(e) => {
 				if (elMatchesStrategy(e.target, 'tap')) {