CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-router-dom

Declarative routing for React web applications

Pending
Overview
Eval results
Files

utilities.mddocs/

Utilities

Path manipulation utilities, route matching functions, and data response helpers for advanced routing scenarios.

Capabilities

Path Utilities

Functions for working with URL paths and route patterns.

/**
 * Generate path from pattern and parameters
 * @param path - Path pattern with parameter placeholders
 * @param params - Parameter values to substitute
 * @returns Generated path string
 */
function generatePath<T extends Record<string, any>>(
  path: string,
  params?: T
): string;

Usage Examples:

import { generatePath } from "react-router-dom";

// Basic parameter substitution
const userPath = generatePath("/users/:userId", { userId: "123" });
// Result: "/users/123"

// Multiple parameters
const postPath = generatePath("/users/:userId/posts/:postId", {
  userId: "123",
  postId: "abc"
});
// Result: "/users/123/posts/abc"

// Optional parameters
const searchPath = generatePath("/search/:category?", { category: "books" });
// Result: "/search/books"

const searchPathEmpty = generatePath("/search/:category?", {});
// Result: "/search"

// Complex patterns
const filePath = generatePath("/files/*", { "*": "documents/report.pdf" });
// Result: "/files/documents/report.pdf"
/**
 * Resolve relative path against current location
 * @param to - Path to resolve (relative or absolute)
 * @param fromPathname - Base pathname to resolve from
 * @returns Resolved path object
 */
function resolvePath(to: To, fromPathname?: string): Path;

type To = string | Partial<Path>;

interface Path {
  /** Resolved pathname */
  pathname: string;
  /** Query string */
  search: string;
  /** Hash fragment */
  hash: string;
}

Usage Examples:

import { resolvePath } from "react-router-dom";

// Resolve relative paths
const resolved = resolvePath("../settings", "/users/123/profile");
// Result: { pathname: "/users/123/settings", search: "", hash: "" }

// Resolve with search and hash
const resolvedComplex = resolvePath({
  pathname: "./edit",
  search: "?tab=general",
  hash: "#form"
}, "/users/123");
// Result: { pathname: "/users/123/edit", search: "?tab=general", hash: "#form" }

// Absolute paths are returned as-is
const absolute = resolvePath("/admin/dashboard");
// Result: { pathname: "/admin/dashboard", search: "", hash: "" }

Route Matching

Functions for matching routes against URL paths.

/**
 * Match path against a pattern
 * @param pattern - Pattern to match against (string or PathPattern object)
 * @param pathname - URL pathname to match
 * @returns Match object with parameters, or null if no match
 */
function matchPath<T extends Record<string, any>>(
  pattern: PathPattern<T> | string,
  pathname: string
): PathMatch<T> | null;

interface PathPattern<T extends Record<string, any> = Record<string, any>> {
  /** Path pattern with parameter placeholders */
  path: string;
  /** Enable case-sensitive matching */
  caseSensitive?: boolean;
  /** Match entire path (true) or just beginning (false) */
  end?: boolean;
}

interface PathMatch<T extends Record<string, any> = Record<string, any>> {
  /** Extracted route parameters */
  params: T;
  /** Matched portion of pathname */
  pathname: string;
  /** Base pathname for nested matches */
  pathnameBase: string;
  /** Pattern used for matching */
  pattern: PathPattern<T>;
}

Usage Examples:

import { matchPath } from "react-router-dom";

// Basic pattern matching
const match = matchPath("/users/:id", "/users/123");
// Result: { 
//   params: { id: "123" }, 
//   pathname: "/users/123",
//   pathnameBase: "/users/123",
//   pattern: { path: "/users/:id", end: true }
// }

// Pattern with options
const optionalMatch = matchPath(
  { path: "/posts/:slug", caseSensitive: true, end: false },
  "/posts/hello-world/comments"
);
// Result: {
//   params: { slug: "hello-world" },
//   pathname: "/posts/hello-world",
//   pathnameBase: "/posts/hello-world",
//   pattern: { path: "/posts/:slug", caseSensitive: true, end: false }
// }

// No match
const noMatch = matchPath("/users/:id", "/posts/123");
// Result: null

// Wildcard matching
const wildcardMatch = matchPath("/files/*", "/files/docs/readme.txt");
// Result: {
//   params: { "*": "docs/readme.txt" },
//   pathname: "/files/docs/readme.txt",
//   pathnameBase: "/files",
//   pattern: { path: "/files/*", end: true }
// }
/**
 * Match multiple routes against location
 * @param routes - Array of route objects to match
 * @param location - Location object or pathname string
 * @param basename - Base URL for matching
 * @returns Array of matched routes, or null if no matches
 */
function matchRoutes(
  routes: RouteObject[],
  location: Partial<Location> | string,
  basename?: string
): RouteMatch[] | null;

interface RouteMatch<ParamKey extends string = string> {
  /** Matched route parameters */
  params: Params<ParamKey>;
  /** Matched pathname portion */
  pathname: string;
  /** Base pathname for this match */
  pathnameBase: string;
  /** Route definition that matched */
  route: RouteObject;
}

interface RouteObject {
  path?: string;
  index?: boolean;
  children?: RouteObject[];
  caseSensitive?: boolean;
  id?: string;
  loader?: LoaderFunction;
  action?: ActionFunction;
  element?: React.ReactNode | null;
  errorElement?: React.ReactNode | null;
}

Usage Examples:

import { matchRoutes } from "react-router-dom";

const routes = [
  {
    path: "/",
    children: [
      { index: true, element: <Home /> },
      { path: "about", element: <About /> },
      {
        path: "users/:id",
        element: <User />,
        children: [
          { path: "profile", element: <Profile /> },
          { path: "settings", element: <Settings /> },
        ],
      },
    ],
  },
];

// Match nested route
const matches = matchRoutes(routes, "/users/123/profile");
// Result: [
//   { params: {}, pathname: "/", pathnameBase: "/", route: routes[0] },
//   { params: { id: "123" }, pathname: "/users/123", pathnameBase: "/users/123", route: userRoute },
//   { params: { id: "123" }, pathname: "/users/123/profile", pathnameBase: "/users/123/profile", route: profileRoute }
// ]

// No matches
const noMatches = matchRoutes(routes, "/nonexistent");
// Result: null

Data Response Helpers

Functions for creating responses in loaders and actions.

/**
 * Create response with JSON data
 * @param data - Data to serialize as JSON
 * @param init - Response initialization options
 * @returns Response object with JSON data
 */
function data<T>(data: T, init?: number | ResponseInit): Response;

/**
 * Create redirect response
 * @param url - URL to redirect to
 * @param init - Response status code or initialization options
 * @returns Redirect response
 */
function redirect(url: string, init?: number | ResponseInit): Response;

/**
 * Create document redirect response (full page reload)
 * @param url - URL to redirect to  
 * @param init - Response initialization options
 * @returns Document redirect response
 */
function redirectDocument(url: string, init?: ResponseInit): Response;

/**
 * Create replace response (replaces current history entry)
 * @param url - URL to replace with
 * @param init - Response initialization options
 * @returns Replace response
 */
function replace(url: string, init?: ResponseInit): Response;

Usage Examples:

import { data, redirect, json } from "react-router-dom";

// Basic data response
export const loader = async () => {
  const users = await fetchUsers();
  return data(users);
};

// Data response with headers
export const loaderWithHeaders = async () => {
  const posts = await fetchPosts();
  return data(posts, {
    headers: {
      "Cache-Control": "public, max-age=300",
      "X-Custom-Header": "value",
    },
  });
};

// Redirect responses
export const actionWithRedirect = async ({ request }) => {
  const formData = await request.formData();
  const user = await createUser(formData);
  
  // Redirect to user profile
  return redirect(`/users/${user.id}`);
};

// Conditional redirect
export const protectedLoader = async ({ request }) => {
  const user = await getUser(request);
  
  if (!user) {
    return redirect("/login");
  }
  
  return data({ user });
};

// Error responses
export const loaderWithError = async ({ params }) => {
  const user = await fetchUser(params.id);
  
  if (!user) {
    throw data("User not found", { status: 404 });
  }
  
  return data(user);
};

Error Response Utilities

Functions for working with error responses.

/**
 * Check if error is a route error response
 * @param error - Error object to check
 * @returns True if error is a route error response
 */
function isRouteErrorResponse(error: any): error is ErrorResponse;

interface ErrorResponse {
  /** HTTP status code */
  status: number;
  /** HTTP status text */
  statusText: string;
  /** Response data */
  data: any;
  /** Internal error flag */
  internal: boolean;
}

Usage Examples:

import { isRouteErrorResponse, useRouteError } from "react-router-dom";

function ErrorBoundary() {
  const error = useRouteError();
  
  if (isRouteErrorResponse(error)) {
    return (
      <div>
        <h1>{error.status} {error.statusText}</h1>
        <p>{error.data}</p>
      </div>
    );
  }
  
  // Handle other error types
  return (
    <div>
      <h1>Something went wrong!</h1>
      <p>{error?.message || "Unknown error"}</p>
    </div>
  );
}

URL Search Parameters

Functions for working with URL search parameters.

/**
 * Create URLSearchParams instance from various input types
 * @param init - Initial search parameters
 * @returns URLSearchParams instance
 */
function createSearchParams(init?: URLSearchParamsInit): URLSearchParams;

type URLSearchParamsInit = 
  | string 
  | string[][] 
  | Record<string, string | string[]> 
  | URLSearchParams;

Usage Examples:

import { createSearchParams } from "react-router-dom";

// From string
const params1 = createSearchParams("?q=react&category=library");

// From object
const params2 = createSearchParams({
  q: "react",
  category: "library",
  sort: "popularity"
});

// From array of arrays
const params3 = createSearchParams([
  ["q", "react"],
  ["category", "library"],
  ["tag", "frontend"],
  ["tag", "javascript"] // Multiple values for same key
]);

// From existing URLSearchParams
const existingParams = new URLSearchParams("?page=1");
const params4 = createSearchParams(existingParams);

// Usage in loaders
export const loader = async ({ request }) => {
  const url = new URL(request.url);
  const searchParams = createSearchParams(url.search);
  
  const query = searchParams.get("q") || "";
  const page = parseInt(searchParams.get("page") || "1");
  
  const results = await searchPosts(query, page);
  return data({ results, query, page });
};

Hook Utilities

Additional utility functions for working with router hooks.

/**
 * Create custom link click handler
 * @param to - Navigation destination
 * @param options - Navigation options
 * @returns Click handler function
 */
function useLinkClickHandler<E extends Element = HTMLAnchorElement>(
  to: To,
  options?: {
    target?: React.HTMLAttributeAnchorTarget;
    replace?: boolean;
    state?: any;
    preventScrollReset?: boolean;
    relative?: RelativeRoutingType;
  }
): (event: React.MouseEvent<E, MouseEvent>) => void;

/**
 * Create form submission handler
 * @returns Submit function for programmatic form submission
 */
function useSubmit(): SubmitFunction;

type SubmitFunction = (
  target: SubmitTarget,
  options?: SubmitOptions
) => void;

type SubmitTarget = 
  | HTMLFormElement 
  | FormData 
  | URLSearchParams 
  | { [name: string]: string | File | (string | File)[] };

interface SubmitOptions {
  action?: string;
  method?: "get" | "post" | "put" | "patch" | "delete";
  encType?: "application/x-www-form-urlencoded" | "multipart/form-data";
  replace?: boolean;
  preventScrollReset?: boolean;
  relative?: RelativeRoutingType;
  unstable_flushSync?: boolean;
}

Usage Examples:

import { useLinkClickHandler, useSubmit } from "react-router-dom";

// Custom link component
function CustomLink({ to, children, ...props }) {
  const handleClick = useLinkClickHandler(to, {
    replace: props.replace,
    state: props.state,
  });
  
  return (
    <a {...props} onClick={handleClick}>
      {children}
    </a>
  );
}

// Programmatic form submission
function SearchComponent() {
  const submit = useSubmit();
  
  const handleQuickSearch = (query: string) => {
    submit(
      { q: query },
      { method: "get", action: "/search" }
    );
  };
  
  const handleFileUpload = (file: File) => {
    const formData = new FormData();
    formData.append("file", file);
    
    submit(formData, {
      method: "post",
      action: "/upload",
      encType: "multipart/form-data",
    });
  };
  
  return (
    <div>
      <button onClick={() => handleQuickSearch("react")}>
        Quick Search
      </button>
      <input 
        type="file" 
        onChange={(e) => e.target.files?.[0] && handleFileUpload(e.target.files[0])}
      />
    </div>
  );
}

Utility Patterns

Path Generation

// Generate paths for navigation
const routes = {
  home: () => "/",
  user: (id: string) => generatePath("/users/:id", { id }),
  userPost: (userId: string, postId: string) => 
    generatePath("/users/:userId/posts/:postId", { userId, postId }),
  search: (query: string, filters?: Record<string, string>) => {
    const params = createSearchParams({ q: query, ...filters });
    return `/search?${params}`;
  },
};

// Usage
<Link to={routes.user("123")}>User Profile</Link>
<Link to={routes.userPost("123", "abc")}>User Post</Link>

Route Matching for Components

// Conditional rendering based on route matching
function NavigationBreadcrumbs() {
  const location = useLocation();
  
  const userMatch = matchPath("/users/:id", location.pathname);
  const postMatch = matchPath("/users/:id/posts/:postId", location.pathname);
  
  const crumbs = ["Home"];
  
  if (userMatch) {
    crumbs.push(`User ${userMatch.params.id}`);
  }
  
  if (postMatch) {
    crumbs.push(`Post ${postMatch.params.postId}`);
  }
  
  return (
    <nav>
      {crumbs.map((crumb, index) => (
        <span key={index}>
          {crumb}
          {index < crumbs.length - 1 && " > "}
        </span>
      ))}
    </nav>
  );
}

Error Response Handling

// Comprehensive error handling
export const loader = async ({ params }) => {
  try {
    const user = await fetchUser(params.id);
    
    if (!user) {
      throw data("User not found", { 
        status: 404,
        statusText: "Not Found" 
      });
    }
    
    if (!user.isPublic && !await canViewUser(user.id)) {
      throw data("Access denied", { 
        status: 403,
        statusText: "Forbidden" 
      });
    }
    
    return data(user);
  } catch (error) {
    if (error instanceof Response) {
      throw error; // Re-throw Response errors
    }
    
    console.error("Loader error:", error);
    throw data("Failed to load user", { 
      status: 500,
      statusText: "Internal Server Error" 
    });
  }
};

Navigation Constants

Constants representing different navigation and loading states.

/**
 * Constant representing idle navigation state
 */
const IDLE_NAVIGATION: Navigation;

/**
 * Constant representing idle fetcher state
 */
const IDLE_FETCHER: Fetcher;

/**
 * Constant representing idle blocker state
 */
const IDLE_BLOCKER: Blocker;

interface Navigation {
  state: "idle" | "loading" | "submitting";
  location?: Location;
  formMethod?: FormMethod;
  formAction?: string;
  formEncType?: FormEncType;
  formData?: FormData;
}

interface Fetcher {
  state: "idle" | "loading" | "submitting";
  data?: any;
  formMethod?: FormMethod;
  formAction?: string;
  formEncType?: FormEncType;
  formData?: FormData;
}

interface Blocker {
  state: "unblocked" | "blocked" | "proceeding";
  proceed?: () => void;
  reset?: () => void;
  location?: Location;
}

Usage Examples:

import { 
  IDLE_NAVIGATION, 
  IDLE_FETCHER, 
  IDLE_BLOCKER,
  useNavigation,
  useFetcher,
  useBlocker
} from "react-router-dom";

function NavigationStatus() {
  const navigation = useNavigation();
  const fetcher = useFetcher();
  const blocker = useBlocker(false);
  
  return (
    <div>
      <p>
        Navigation: {navigation.state === IDLE_NAVIGATION.state ? "Idle" : "Active"}
      </p>
      <p>
        Fetcher: {fetcher.state === IDLE_FETCHER.state ? "Idle" : "Active"}
      </p>
      <p>
        Blocker: {blocker.state === IDLE_BLOCKER.state ? "Unblocked" : blocker.state}
      </p>
    </div>
  );
}

// Checking for idle states in effects
function DataComponent() {
  const navigation = useNavigation();
  
  useEffect(() => {
    if (navigation.state === IDLE_NAVIGATION.state) {
      // Navigation completed, update UI
      console.log("Navigation completed");
    }
  }, [navigation.state]);
  
  return <div>Content</div>;
}

Install with Tessl CLI

npx tessl i tessl/npm-react-router-dom

docs

data-loading-hooks.md

index.md

navigation-components.md

navigation-hooks.md

route-configuration.md

router-components.md

router-creation.md

server-side-rendering.md

utilities.md

tile.json