Minimalist-friendly ~1.5KB router for React
Programmatic hooks for accessing and controlling routing state, including location management, route matching, parameter extraction, and router configuration access.
Returns the current location and a navigation function, providing the primary interface for location-aware components and navigation logic.
/**
* Hook for accessing current location and navigation function
* @returns Tuple of [currentPath, navigateFunction]
*/
function useLocation<H extends BaseLocationHook = BrowserLocationHook>(): HookReturnValue<H>;
type HookReturnValue<H extends BaseLocationHook> = ReturnType<H>;Usage Examples:
import { useLocation } from "wouter";
function MyComponent() {
const [location, navigate] = useLocation();
// Current path
console.log(location); // "/users/123"
// Navigate programmatically
const handleClick = () => {
navigate("/dashboard");
};
// Navigate with options
const handleReplace = () => {
navigate("/settings", { replace: true });
};
return (
<div>
<p>Current location: {location}</p>
<button onClick={handleClick}>Go to Dashboard</button>
<button onClick={handleReplace}>Replace with Settings</button>
</div>
);
}Matches a route pattern against the current location and extracts parameters, useful for conditional rendering and parameter access outside of Route components.
/**
* Hook for matching route patterns and extracting parameters
* @param pattern - Route pattern to match (string with :param syntax or RegExp)
* @returns Match result tuple - [isMatch, params] or [false, null]
*/
function useRoute<T extends DefaultParams | undefined = undefined, RoutePath extends PathPattern = PathPattern>(
pattern: RoutePath
): Match<T extends DefaultParams ? T : RoutePath extends string ? StringRouteParams<RoutePath> : RegexRouteParams>;
type Match<T extends DefaultParams = DefaultParams> =
| [true, Params<T>]
| [false, null];Usage Examples:
import { useRoute } from "wouter";
function UserProfile() {
const [match, params] = useRoute("/users/:id");
if (!match) {
return <div>Not on user profile page</div>;
}
return (
<div>
<h1>User Profile</h1>
<p>User ID: {params.id}</p>
</div>
);
}
function ConditionalNav() {
const [isOnDashboard] = useRoute("/dashboard");
const [isOnSettings] = useRoute("/settings");
return (
<nav className={isOnDashboard ? "dashboard-nav" : "default-nav"}>
{isOnSettings && <SettingsMenu />}
</nav>
);
}Provides access to the current router configuration and context, useful for accessing routing options and creating custom navigation logic.
/**
* Hook for accessing current router context and configuration
* @returns RouterObject with current routing configuration
*/
function useRouter(): RouterObject;
interface RouterObject {
/** Current location hook being used */
readonly hook: BaseLocationHook;
/** Current search hook for query parameters */
readonly searchHook: BaseSearchHook;
/** Base path for all routes */
readonly base: Path;
/** Own base path (without inherited base) */
readonly ownBase: Path;
/** Route pattern parser function */
readonly parser: Parser;
/** Static SSR path if configured */
readonly ssrPath?: Path;
/** Static SSR search string if configured */
readonly ssrSearch?: SearchString;
/** HREF formatting function */
readonly hrefs: HrefsFormatter;
}Usage Examples:
import { useRouter } from "wouter";
function RouterInfo() {
const router = useRouter();
return (
<div>
<p>Base path: {router.base}</p>
<p>Using SSR: {router.ssrPath ? "Yes" : "No"}</p>
</div>
);
}
function CustomNavigation() {
const router = useRouter();
const [location, navigate] = router.hook(router);
const handleNavigate = (path: string) => {
// Custom navigation logic with base path
const fullPath = router.base + path;
navigate(fullPath);
};
return (
<button onClick={() => handleNavigate("/custom")}>
Custom Navigate
</button>
);
}Accesses route parameters from the nearest Route component context, providing a convenient way to get matched parameters in nested components.
/**
* Hook for accessing route parameters from nearest Route context
* @returns Object containing matched route parameters
*/
function useParams<T = undefined>(): T extends string
? StringRouteParams<T>
: T extends undefined
? DefaultParams
: T;
interface DefaultParams {
readonly [paramName: string | number]: string | undefined;
}Usage Examples:
import { useParams } from "wouter";
// Inside a Route with path="/users/:id/posts/:postId"
function PostDetail() {
const params = useParams();
return (
<div>
<h1>Post {params.postId}</h1>
<p>By user {params.id}</p>
</div>
);
}
// With type safety
function TypedPostDetail() {
const params = useParams<"/users/:userId/posts/:postId">();
// params.userId and params.postId are typed
return (
<div>
<h1>Post {params.postId}</h1>
<p>By user {params.userId}</p>
</div>
);
}Accesses the current URL search/query string, providing access to query parameters separately from the main location path.
/**
* Hook for accessing URL search/query parameters
* @returns Current search string (without leading ?)
*/
function useSearch<H extends BaseSearchHook = BrowserSearchHook>(): ReturnType<H>;
type BaseSearchHook = (...args: any[]) => SearchString;
type BrowserSearchHook = (options?: { ssrSearch?: SearchString }) => SearchString;Usage Examples:
import { useSearch } from "wouter";
function SearchExample() {
const search = useSearch();
// Parse search manually
const params = new URLSearchParams(search);
const query = params.get("q");
const page = params.get("page");
return (
<div>
<p>Search query: {query}</p>
<p>Current page: {page}</p>
<p>Full search: {search}</p>
</div>
);
}Provides managed access to URL search parameters with a setter function, similar to React's useState but for URL search parameters.
/**
* Hook for managing URL search parameters with getter and setter
* @returns Tuple of [URLSearchParams, setSearchParams function]
*/
function useSearchParams(): [URLSearchParams, SetSearchParams];
type SetSearchParams = (
nextInit: URLSearchParamsInit | ((prev: URLSearchParams) => URLSearchParamsInit),
options?: { replace?: boolean; state?: any }
) => void;
type URLSearchParamsInit = ConstructorParameters<typeof URLSearchParams>[0];Usage Examples:
import { useSearchParams } from "wouter";
function SearchForm() {
const [searchParams, setSearchParams] = useSearchParams();
const currentQuery = searchParams.get("q") || "";
const currentPage = parseInt(searchParams.get("page") || "1");
const handleSearch = (query: string) => {
setSearchParams({ q: query, page: "1" });
};
const handlePageChange = (page: number) => {
setSearchParams(prev => {
const newParams = new URLSearchParams(prev);
newParams.set("page", page.toString());
return newParams;
});
};
return (
<div>
<input
value={currentQuery}
onChange={(e) => handleSearch(e.target.value)}
placeholder="Search..."
/>
<p>Page: {currentPage}</p>
<button onClick={() => handlePageChange(currentPage + 1)}>
Next Page
</button>
</div>
);
}
function FilterControls() {
const [searchParams, setSearchParams] = useSearchParams();
const setFilter = (key: string, value: string) => {
setSearchParams(
prev => {
const newParams = new URLSearchParams(prev);
newParams.set(key, value);
return newParams;
},
{ replace: true } // Don't add to history
);
};
return (
<div>
<select onChange={(e) => setFilter("category", e.target.value)}>
<option value="">All Categories</option>
<option value="tech">Technology</option>
<option value="design">Design</option>
</select>
</div>
);
}Low-level function for manually matching route patterns against paths, useful for custom routing logic and testing.
/**
* Manually match a route pattern against a path
* @param parser - Route pattern parser function
* @param pattern - Route pattern to match
* @param path - Path to match against
* @param loose - Enable loose matching for nested routes
* @returns Match result tuple - [isMatch, params, base?]
*/
function matchRoute<T extends DefaultParams | undefined = undefined, RoutePath extends PathPattern = PathPattern>(
parser: Parser,
pattern: RoutePath,
path: string,
loose?: boolean
): Match<T extends DefaultParams ? T : RoutePath extends string ? StringRouteParams<RoutePath> : RegexRouteParams>;Usage Examples:
import { matchRoute, useRouter } from "wouter";
function CustomMatcher() {
const { parser } = useRouter();
// Manual route matching
const [matches, params] = matchRoute(parser, "/users/:id", "/users/123");
if (matches) {
console.log("User ID:", params.id); // "123"
}
// Loose matching for nested routes
const [nestedMatch, nestedParams, base] = matchRoute(
parser,
"/admin/:section",
"/admin/users/list",
true
);
if (nestedMatch) {
console.log("Section:", nestedParams.section); // "users"
console.log("Base:", base); // "/admin/users"
}
return <div>Custom matching logic</div>;
}type StringRouteParams<T extends string> = RouteParams<T> & {
[param: number]: string | undefined;
};
type RegexRouteParams = {
[key: string | number]: string | undefined
};
type Params<T extends DefaultParams = DefaultParams> = T;
type HookNavigationOptions<H extends BaseLocationHook> =
EmptyInterfaceWhenAnyOrNever<
NonNullable<Parameters<HookReturnValue<H>[1]>[1]>
>;Install with Tessl CLI
npx tessl i tessl/npm-wouter