diff --git a/.changeset/cyan-poems-clean.md b/.changeset/cyan-poems-clean.md
new file mode 100644
index 0000000000..567cdf9f41
--- /dev/null
+++ b/.changeset/cyan-poems-clean.md
@@ -0,0 +1,6 @@
+---
+"react-router-dom": patch
+"@remix-run/router": patch
+---
+
+properly support index routes with a path in useResolvedPath
diff --git a/packages/react-router-dom/__tests__/data-browser-router-test.tsx b/packages/react-router-dom/__tests__/data-browser-router-test.tsx
index aeffc33c19..a8b68ecb82 100644
--- a/packages/react-router-dom/__tests__/data-browser-router-test.tsx
+++ b/packages/react-router-dom/__tests__/data-browser-router-test.tsx
@@ -1737,6 +1737,29 @@ function testDomRouter(
await new Promise((r) => setTimeout(r, 0));
assertLocation(testWindow, "/form", "?index");
});
+
+ it("handles index routes with a path", async () => {
+ let { container } = render(
+
+
+
+ }
+ />
+
+
+
+ );
+
+ expect(container.querySelector("form")?.getAttribute("action")).toBe(
+ "/foo/bar?index&a=1#hash"
+ );
+ });
});
describe("dynamic routes", () => {
diff --git a/packages/react-router/lib/hooks.tsx b/packages/react-router/lib/hooks.tsx
index 76350418ad..5909e76fd9 100644
--- a/packages/react-router/lib/hooks.tsx
+++ b/packages/react-router/lib/hooks.tsx
@@ -19,6 +19,7 @@ import {
parsePath,
resolveTo,
warning,
+ UNSAFE_getPathContributingMatches as getPathContributingMatches,
} from "@remix-run/router";
import type {
@@ -147,36 +148,6 @@ export interface NavigateFunction {
(delta: number): void;
}
-/**
- * When processing relative navigation we want to ignore ancestor routes that
- * do not contribute to the path, such that index/pathless layout routes don't
- * interfere.
- *
- * For example, when moving a route element into an index route and/or a
- * pathless layout route, relative link behavior contained within should stay
- * the same. Both of the following examples should link back to the root:
- *
- *
- *
- *
- *
- *
- *
- * }> // <-- Does not contribute
- * // <-- Does not contribute
- *
- *
- */
-function getPathContributingMatches(matches: RouteMatch[]) {
- return matches.filter(
- (match, index) =>
- index === 0 ||
- (!match.route.index &&
- match.pathnameBase !== matches[index - 1].pathnameBase)
- );
-}
-
/**
* Returns an imperative method for changing the location. Used by s, but
* may also be used by other elements to change the location.
diff --git a/packages/router/index.ts b/packages/router/index.ts
index 4196adc3f4..f9739ba566 100644
--- a/packages/router/index.ts
+++ b/packages/router/index.ts
@@ -1,4 +1,4 @@
-import { convertRoutesToDataRoutes } from "./utils";
+import { convertRoutesToDataRoutes, getPathContributingMatches } from "./utils";
export type {
ActionFunction,
@@ -79,4 +79,7 @@ export * from "./router";
///////////////////////////////////////////////////////////////////////////////
/** @internal */
-export { convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes };
+export {
+ convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes,
+ getPathContributingMatches as UNSAFE_getPathContributingMatches,
+};
diff --git a/packages/router/utils.ts b/packages/router/utils.ts
index 308901d5a8..70761f6146 100644
--- a/packages/router/utils.ts
+++ b/packages/router/utils.ts
@@ -857,6 +857,8 @@ function getInvalidPathError(
}
/**
+ * @private
+ *
* When processing relative navigation we want to ignore ancestor routes that
* do not contribute to the path, such that index/pathless layout routes don't
* interfere.
@@ -882,9 +884,7 @@ export function getPathContributingMatches<
>(matches: T[]) {
return matches.filter(
(match, index) =>
- index === 0 ||
- (!match.route.index &&
- match.pathnameBase !== matches[index - 1].pathnameBase)
+ index === 0 || (match.route.path && match.route.path.length > 0)
);
}