diff --git a/packages/jarl-react/src/__tests__/hooks.test.tsx b/packages/jarl-react/src/__tests__/hooks.test.tsx
index b098536d..8ef8d152 100644
--- a/packages/jarl-react/src/__tests__/hooks.test.tsx
+++ b/packages/jarl-react/src/__tests__/hooks.test.tsx
@@ -1,4 +1,4 @@
-import { describe, it, expect, beforeEach } from "vitest";
+import { describe, it, expect, beforeEach, vi } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import { rootAtom } from "jarl-atoms";
import { useRoute, useNavigate, useIsActive, useHref, useLink } from "../hooks";
@@ -51,6 +51,21 @@ describe("useNavigate", () => {
expect(screen.getByTestId("match")).toHaveTextContent("true");
expect(window.location.pathname).toBe("/about");
});
+
+ it("forwards { replace: true } as a replace navigation", () => {
+ goTo("/");
+ const pushSpy = vi.spyOn(window.history, "pushState");
+ const replaceSpy = vi.spyOn(window.history, "replaceState");
+ const Probe = () => {
+ const navigate = useNavigate(aboutAtom);
+ return ;
+ };
+ render();
+ fireEvent.click(screen.getByText("Go"));
+ expect(replaceSpy).toHaveBeenCalled();
+ expect(pushSpy).not.toHaveBeenCalled();
+ expect(window.location.pathname).toBe("/about");
+ });
});
describe("useIsActive", () => {
diff --git a/packages/jarl-react/src/hooks.ts b/packages/jarl-react/src/hooks.ts
index 68a9ad40..caba6b4c 100644
--- a/packages/jarl-react/src/hooks.ts
+++ b/packages/jarl-react/src/hooks.ts
@@ -1,6 +1,6 @@
import { useCallback, useMemo } from "react";
import { useAtom, useAtomValue, useSetAtom } from "jotai";
-import { DefaultParams, RouteAtom } from "jarl-atoms";
+import { DefaultParams, NavOptions, RouteAtom } from "jarl-atoms";
import { isActive } from "./isActive";
// Re-export jotai's own primitive hooks. Per jotai convention (see
@@ -21,11 +21,12 @@ export function useRoute(routeAtom: RouteAtom) {
/**
* Returns a stable `navigate` function bound to one route atom. Calling it with param values
- * pushes a new location.
+ * pushes a new location; pass `{ replace: true }` as a second argument for a replace navigation,
+ * mirroring the route atom's own setter (`set(routeAtom, values, { replace: true })`).
*/
export function useNavigate(routeAtom: RouteAtom) {
const setRoute = useSetAtom(routeAtom);
- return useCallback((to: T) => setRoute(to), [setRoute]);
+ return useCallback((to: T, options?: NavOptions) => setRoute(to, options), [setRoute]);
}
/**