Skip to main content

Summary

Returns a resolved Path object relative to the given pathname. Handles relative navigation like .. and . similar to how file system paths work. Useful for programmatically resolving paths before navigation or for building URLs.

Signature

function resolvePath(
  to: To,
  fromPathname?: string
): Path

Parameters

to
To
required
The path to resolve. Can be:
  • A string path (e.g., "../users", "/dashboard")
  • A partial Path object with pathname, search, and hash
Supports relative paths with .. (parent) and . (current).
fromPathname
string
default:"/"
The pathname to resolve from. Acts as the “current location” for relative path resolution.

Path Object

interface Path {
  pathname: string;  // URL pathname
  search: string;    // Query string (with leading "?")
  hash: string;      // Hash fragment (with leading "#")
}

Returns

path
Path
A Path object with resolved pathname, search, and hash properties.

Examples

Absolute paths

import { resolvePath } from "react-router";

resolvePath("/users", "/dashboard");
// { pathname: "/users", search: "", hash: "" }

// Absolute paths ignore fromPathname
resolvePath("/about", "/any/current/path");
// { pathname: "/about", search: "", hash: "" }

Relative paths

import { resolvePath } from "react-router";

// Relative to current directory
resolvePath("posts", "/users");
// { pathname: "/users/posts", search: "", hash: "" }

// Current directory
resolvePath(".", "/users/123");
// { pathname: "/users/123", search: "", hash: "" }

Parent directory navigation

import { resolvePath } from "react-router";

// Go up one level
resolvePath("..", "/users/123");
// { pathname: "/users", search: "", hash: "" }

// Go up two levels
resolvePath("../..", "/users/123/posts");
// { pathname: "/users", search: "", hash: "" }

// Go up and into sibling
resolvePath("../settings", "/users/123");
// { pathname: "/users/settings", search: "", hash: "" }

With search and hash

import { resolvePath } from "react-router";

resolvePath("/search?q=react#results", "/");
// {
//   pathname: "/search",
//   search: "?q=react",
//   hash: "#results"
// }

// Using Path object
resolvePath(
  {
    pathname: "../users",
    search: "?page=2",
    hash: "#top",
  },
  "/dashboard/settings"
);
// {
//   pathname: "/dashboard/users",
//   search: "?page=2",
//   hash: "#top"
// }

Complex relative paths

import { resolvePath } from "react-router";

// Multiple parent navigations
resolvePath("../../posts/new", "/users/123/settings");
// { pathname: "/users/posts/new", search: "", hash: "" }

// Mixed absolute and relative
resolvePath("/users/../posts", "/dashboard");
// { pathname: "/posts", search: "", hash: "" }

Common Use Cases

Building navigation URLs

import { resolvePath, useLocation } from "react-router";

function BackButton() {
  const location = useLocation();
  const backPath = resolvePath("..", location.pathname);
  
  return (
    <Link to={backPath.pathname}>
      Back
    </Link>
  );
}
import { resolvePath, useNavigate, useLocation } from "react-router";

function useRelativeNavigate() {
  const navigate = useNavigate();
  const location = useLocation();
  
  return (to: string) => {
    const resolved = resolvePath(to, location.pathname);
    navigate(resolved.pathname + resolved.search + resolved.hash);
  };
}

Generating canonical URLs

import { resolvePath } from "react-router";

function getCanonicalUrl(relativePath: string, currentPath: string): string {
  const resolved = resolvePath(relativePath, currentPath);
  return `https://example.com${resolved.pathname}${resolved.search}${resolved.hash}`;
}

const url = getCanonicalUrl("../about", "/products/shoes");
// "https://example.com/products/about"
import { resolvePath } from "react-router";

function getBreadcrumbPaths(pathname: string) {
  const segments = pathname.split("/").filter(Boolean);
  const breadcrumbs = [];
  
  for (let i = 0; i < segments.length; i++) {
    const path = "/" + segments.slice(0, i + 1).join("/");
    breadcrumbs.push({
      label: segments[i],
      path: resolvePath(path, "/").pathname,
    });
  }
  
  return breadcrumbs;
}

getBreadcrumbPaths("/users/123/posts");
// [
//   { label: "users", path: "/users" },
//   { label: "123", path: "/users/123" },
//   { label: "posts", path: "/users/123/posts" }
// ]

Validating relative paths

import { resolvePath } from "react-router";

function isValidRelativePath(
  to: string,
  from: string,
  allowedBase: string
): boolean {
  const resolved = resolvePath(to, from);
  return resolved.pathname.startsWith(allowedBase);
}

// Ensure navigation stays within /app
isValidRelativePath("../settings", "/app/dashboard", "/app"); // true
isValidRelativePath("../../admin", "/app/dashboard", "/app"); // false

Path Resolution Rules

Absolute paths

Paths starting with / are absolute and ignore fromPathname:
resolvePath("/users", "/dashboard");
// Always resolves to "/users"

Relative paths

Paths without leading / are relative to fromPathname:
resolvePath("settings", "/users/123");
// Resolves to "/users/123/settings"

Parent directory (..)

Each .. goes up one directory level:
resolvePath("..", "/users/123/posts");
// Resolves to "/users/123"

resolvePath("../..", "/users/123/posts");
// Resolves to "/users"

resolvePath("../../..", "/users/123/posts");
// Resolves to "/" (root, can't go higher)

Current directory (.)

Stays at the current level:
resolvePath(".", "/users/123");
// Resolves to "/users/123"

resolvePath("./posts", "/users/123");
// Resolves to "/users/123/posts" (same as "posts")

Empty paths

resolvePath("", "/users/123");
// Resolves to "/users/123"

Search and Hash Handling

Search params are preserved

resolvePath("?page=2", "/users");
// { pathname: "/users", search: "?page=2", hash: "" }

Hash fragments are preserved

resolvePath("#section", "/users");
// { pathname: "/users", search: "", hash: "#section" }

Combined

resolvePath("../posts?sort=date#top", "/users/123");
// {
//   pathname: "/users/posts",
//   search: "?sort=date",
//   hash: "#top"
// }

Edge Cases

Too many parent references

resolvePath("../../../../..", "/users/123");
// Resolves to "/" (stops at root)

Trailing slashes

resolvePath("users/", "/");
// { pathname: "/users/", search: "", hash: "" }
// Trailing slash is preserved

Empty pathname

resolvePath({ search: "?q=test" }, "/users");
// { pathname: "/users", search: "?q=test", hash: "" }

Type Safety

TypeScript ensures proper types:
import { resolvePath, Path } from "react-router";

const path: Path = resolvePath("/users", "/");
const pathname: string = path.pathname; // ✓
const search: string = path.search;     // ✓
const hash: string = path.hash;         // ✓

Performance

Path resolution is a synchronous, fast operation suitable for use in render functions:
function MyComponent() {
  const location = useLocation();
  
  // Fine to call in render
  const backPath = resolvePath("..", location.pathname);
  
  return <Link to={backPath.pathname}>Back</Link>;
}

Notes

  • Always returns a complete Path object with all three properties
  • Search params should include the leading ?
  • Hash fragments should include the leading #
  • Root path is / and cannot be navigated above
  • Relative paths are resolved similar to file system paths
  • Empty pathname in to object uses fromPathname

Build docs developers (and LLMs) love