diff --git a/docs/advanced-guides/custom-links.md b/docs/advanced-guides/custom-links.md
index afcaeff015..1e9060cc3b 100644
--- a/docs/advanced-guides/custom-links.md
+++ b/docs/advanced-guides/custom-links.md
@@ -1,3 +1,54 @@
# Custom Links
-TODO
+In most cases, the exported `` component should meet all of your needs as an abstraction of the anchor tag. If you need to return anything other than an anchor element, or override any of ``'s rendering logic, you can use a few hooks from `react-router-dom` to build your own:
+
+```tsx
+import { useHref, useLinkClickHandler } from "react-router-dom";
+
+const StyledLink = styled("a", { color: "fuschia" });
+
+const Link = React.forwardRef(
+ ({ onClick, replace = false, state, target, to, ...rest }, ref) => {
+ let href = useHref(to);
+ let handleClick = useLinkClickHandler(to, { replace, state, target });
+
+ return (
+ {
+ onClick?.(event);
+ if (!event.defaultPrevented) {
+ handleClick(event);
+ }
+ }}
+ ref={ref}
+ target={target}
+ />
+ );
+ }
+);
+```
+
+If you're using `react-router-native`, you can create a custom `` with the `useLinkPressHandler` hook:
+
+```tsx
+import { TouchableHighlight } from "react-native";
+import { useLinkPressHandler } from "react-router-native";
+
+function Link({ onPress, replace = false, state, to, ...rest }) {
+ let handlePress = useLinkPressHandler(to, { replace, state });
+
+ return (
+ {
+ onPress?.(event);
+ if (!event.defaultPrevented) {
+ handlePress(event);
+ }
+ }}
+ />
+ );
+}
+```
diff --git a/docs/api-reference.md b/docs/api-reference.md
index 1325fb2ee3..898a3854c5 100644
--- a/docs/api-reference.md
+++ b/docs/api-reference.md
@@ -69,6 +69,8 @@ There are a few low-level APIs that we use internally that may also prove useful
- [`useResolvedPath`](#useresolvedpath) - resolves a relative path against the current [location](#location)
- [`useHref`](#usehref) - resolves a relative path suitable for use as a ``
+- [`useLinkClickHandler`](#uselinkclickhandler) - returns an event handler to for navigation when building a custom `` in `react-router-dom`
+- [`useLinkPressHandler`](#uselinkpresshandler) - returns an event handler to for navigation when building a custom `` in `react-router-native`
- [`resolvePath`](#resolvepath) - resolves a relative path against a given URL pathname
@@ -892,6 +894,101 @@ The `useHref` hook returns a URL that may be used to link to the given `to` loca
> component in `react-router-dom` to see how it uses `useHref` internally to
> determine its own `href` value.
+
+
+### `useLinkClickHandler`
+
+
+ Type declaration
+
+```tsx
+declare function useLinkClickHandler<
+ E extends Element = HTMLAnchorElement,
+ S extends State = State
+>(
+ to: To,
+ options?: {
+ target?: React.HTMLAttributeAnchorTarget;
+ replace?: boolean;
+ state?: S;
+ }
+): (event: React.MouseEvent) => void;
+```
+
+
+
+The `useLinkClickHandler` hook returns a click event handler to for navigation when building a custom `` in `react-router-dom`.
+
+```tsx
+import { useHref, useLinkClickHandler } from "react-router-dom";
+
+const StyledLink = styled("a", { color: "fuschia" });
+
+const Link = React.forwardRef(
+ ({ onClick, replace = false, state, target, to, ...rest }, ref) => {
+ let href = useHref(to);
+ let handleClick = useLinkClickHandler(to, { replace, state, target });
+
+ return (
+ {
+ onClick?.(event);
+ if (!event.defaultPrevented) {
+ handleClick(event);
+ }
+ }}
+ ref={ref}
+ target={target}
+ />
+ );
+ }
+);
+```
+
+
+
+### `useLinkPressHandler`
+
+
+ Type declaration
+
+```tsx
+declare function useLinkPressHandler(
+ to: To,
+ options?: {
+ replace?: boolean;
+ state?: S;
+ }
+): (event: GestureResponderEvent) => void;
+```
+
+
+
+The `react-router-native` counterpart to `useLinkClickHandler`, `useLinkPressHandler` returns a press event handler for custom `` navigation.
+
+```tsx
+import { TouchableHighlight } from "react-native";
+import { useLinkPressHandler } from "react-router-native";
+
+function Link({ onPress, replace = false, state, to, ...rest }) {
+ let handlePress = useLinkPressHandler(to, { replace, state });
+
+ return (
+ {
+ onPress?.(event);
+ if (!event.defaultPrevented) {
+ handlePress(event);
+ }
+ }}
+ />
+ );
+}
+```
+
### `useInRouterContext`
diff --git a/packages/react-router-dom/__tests__/useLinkClickHandler-test.tsx b/packages/react-router-dom/__tests__/useLinkClickHandler-test.tsx
new file mode 100644
index 0000000000..123b921283
--- /dev/null
+++ b/packages/react-router-dom/__tests__/useLinkClickHandler-test.tsx
@@ -0,0 +1,223 @@
+import * as React from "react";
+import * as ReactDOM from "react-dom";
+import { act } from "react-dom/test-utils";
+import {
+ MemoryRouter as Router,
+ Routes,
+ Route,
+ useHref,
+ useLinkClickHandler
+} from "react-router-dom";
+import type { LinkProps } from "react-router-dom";
+
+describe("Custom link with useLinkClickHandler", () => {
+ let node: HTMLDivElement;
+
+ function Link({ to, replace, state, target, ...rest }: LinkProps) {
+ let href = useHref(to);
+ let handleClick = useLinkClickHandler(to, { target, replace, state });
+ return (
+ // eslint-disable-next-line jsx-a11y/anchor-has-content
+
+ );
+ }
+
+ beforeEach(() => {
+ node = document.createElement("div");
+ document.body.appendChild(node);
+ });
+
+ afterEach(() => {
+ document.body.removeChild(node);
+ node = null!;
+ });
+
+ it("navigates to the new page", () => {
+ function Home() {
+ return (
+