0
# Links & Navigation
1
2
Client-side routing integration, synthetic link handling, and programmatic navigation utilities for React applications.
3
4
## Capabilities
5
6
### Router Integration
7
8
Components and hooks for integrating with client-side routing systems.
9
10
```typescript { .api }
11
/**
12
* Provides client-side navigation context to nested components
13
* @param props - Router configuration
14
* @returns JSX element providing router context
15
*/
16
function RouterProvider(props: {
17
navigate: (path: string) => void;
18
useHref?: (href: string) => string;
19
children: ReactNode;
20
}): JSX.Element;
21
22
/**
23
* Accesses router context for navigation
24
* @returns Router object with navigation methods
25
*/
26
function useRouter(): Router;
27
28
interface Router {
29
/** Whether native browser navigation should be used */
30
isNative: boolean;
31
/** Open link with modifier key handling */
32
open: (target: HTMLAnchorElement, modifiers: Modifiers, setOpening?: boolean) => void;
33
/** Transform href for routing system */
34
useHref?: (href: string) => string;
35
}
36
```
37
38
**Usage Examples:**
39
40
```typescript
41
import { RouterProvider, useRouter } from "@react-aria/utils";
42
43
// App-level router setup
44
function App() {
45
const navigate = (path: string) => {
46
// Your router's navigation function
47
history.push(path);
48
};
49
50
const useHref = (href: string) => {
51
// Transform href for your routing system
52
return `/app${href}`;
53
};
54
55
return (
56
<RouterProvider navigate={navigate} useHref={useHref}>
57
<MainContent />
58
</RouterProvider>
59
);
60
}
61
62
// Using router in components
63
function NavigationComponent() {
64
const router = useRouter();
65
66
const handleLinkClick = (href: string, modifiers: Modifiers) => {
67
if (router.isNative) {
68
// Use browser navigation
69
window.location.href = href;
70
} else {
71
// Use client-side navigation
72
router.open(document.createElement('a'), modifiers);
73
}
74
};
75
76
return <div>Navigation component</div>;
77
}
78
```
79
80
### Link Opening
81
82
Functions for programmatically opening links with modifier key support.
83
84
```typescript { .api }
85
/**
86
* Programmatically opens links with modifier key support
87
* @param target - Anchor element to open
88
* @param modifiers - Object with modifier key states
89
* @param setOpening - Whether to set opening flag for popup blockers
90
*/
91
function openLink(
92
target: HTMLAnchorElement,
93
modifiers: Modifiers,
94
setOpening?: boolean
95
): void;
96
97
/**
98
* Determines if link should use client-side navigation
99
* @param link - Anchor element to check
100
* @param modifiers - Modifier key states
101
* @returns Boolean indicating if router should handle navigation
102
*/
103
function shouldClientNavigate(
104
link: HTMLAnchorElement,
105
modifiers: Modifiers
106
): boolean;
107
108
/**
109
* Handles link clicks with modifier key support
110
* @param target - Anchor element clicked
111
* @param modifiers - Modifier key states from event
112
*/
113
function handleLinkClick(
114
target: HTMLAnchorElement,
115
modifiers: Modifiers
116
): void;
117
118
interface Modifiers {
119
metaKey: boolean;
120
ctrlKey: boolean;
121
altKey: boolean;
122
shiftKey: boolean;
123
}
124
```
125
126
**Usage Examples:**
127
128
```typescript
129
import { openLink, shouldClientNavigate, handleLinkClick } from "@react-aria/utils";
130
131
function SmartLink({ href, children, onClick, ...props }) {
132
const linkRef = useRef<HTMLAnchorElement>(null);
133
134
const handleClick = (e: MouseEvent) => {
135
if (!linkRef.current) return;
136
137
const modifiers = {
138
metaKey: e.metaKey,
139
ctrlKey: e.ctrlKey,
140
altKey: e.altKey,
141
shiftKey: e.shiftKey
142
};
143
144
// Check if we should use client-side navigation
145
if (shouldClientNavigate(linkRef.current, modifiers)) {
146
e.preventDefault();
147
handleLinkClick(linkRef.current, modifiers);
148
} else {
149
// Let browser handle navigation
150
openLink(linkRef.current, modifiers, true);
151
}
152
153
onClick?.(e);
154
};
155
156
return (
157
<a
158
ref={linkRef}
159
href={href}
160
onClick={handleClick}
161
{...props}
162
>
163
{children}
164
</a>
165
);
166
}
167
168
// Link with programmatic opening
169
function ProgrammaticLink({ href, openInNewTab = false }) {
170
const linkRef = useRef<HTMLAnchorElement>(null);
171
172
const handleButtonClick = () => {
173
if (!linkRef.current) return;
174
175
const modifiers = {
176
metaKey: openInNewTab,
177
ctrlKey: openInNewTab,
178
altKey: false,
179
shiftKey: false
180
};
181
182
openLink(linkRef.current, modifiers, true);
183
};
184
185
return (
186
<div>
187
<a ref={linkRef} href={href} style={{ display: 'none' }} />
188
<button onClick={handleButtonClick}>
189
Open Link {openInNewTab ? '(New Tab)' : ''}
190
</button>
191
</div>
192
);
193
}
194
```
195
196
### Synthetic Links
197
198
Utilities for creating non-anchor elements that behave like links.
199
200
```typescript { .api }
201
/**
202
* Creates data attributes for synthetic links
203
* @param props - Link DOM properties
204
* @returns Object with data-* attributes for non-anchor elements
205
*/
206
function getSyntheticLinkProps(props: LinkDOMProps): DOMAttributes<HTMLElement>;
207
208
/**
209
* Hook that creates data attributes for synthetic links
210
* @param props - Link DOM properties
211
* @returns Object with data-* attributes for non-anchor elements
212
*/
213
function useSyntheticLinkProps(props: LinkDOMProps): DOMAttributes<HTMLElement>;
214
215
/**
216
* Hook that processes link props with router context
217
* @param props - Optional link properties
218
* @returns Link props with router-processed href
219
*/
220
function useLinkProps(props?: LinkDOMProps): LinkDOMProps;
221
222
interface LinkDOMProps extends DOMProps {
223
href?: string;
224
target?: string;
225
rel?: string;
226
download?: boolean | string;
227
ping?: string;
228
referrerPolicy?: string;
229
}
230
```
231
232
**Usage Examples:**
233
234
```typescript
235
import { useSyntheticLinkProps, useLinkProps, getSyntheticLinkProps } from "@react-aria/utils";
236
237
// Button that acts like a link
238
function LinkButton({ href, children, ...props }) {
239
const linkProps = useLinkProps({ href, ...props });
240
const syntheticProps = useSyntheticLinkProps(linkProps);
241
242
return (
243
<button
244
{...syntheticProps}
245
onClick={(e) => {
246
// Handle click as link
247
const link = document.createElement('a');
248
link.href = href;
249
handleLinkClick(link, {
250
metaKey: e.metaKey,
251
ctrlKey: e.ctrlKey,
252
altKey: e.altKey,
253
shiftKey: e.shiftKey
254
});
255
}}
256
>
257
{children}
258
</button>
259
);
260
}
261
262
// Card component that's entirely clickable
263
function ClickableCard({ href, title, description }) {
264
const syntheticProps = getSyntheticLinkProps({ href });
265
266
return (
267
<div
268
{...syntheticProps}
269
className="card clickable"
270
role="link"
271
tabIndex={0}
272
onClick={(e) => {
273
const link = document.createElement('a');
274
link.href = href;
275
openLink(link, {
276
metaKey: e.metaKey,
277
ctrlKey: e.ctrlKey,
278
altKey: e.altKey,
279
shiftKey: e.shiftKey
280
});
281
}}
282
onKeyDown={(e) => {
283
if (e.key === 'Enter' || e.key === ' ') {
284
e.preventDefault();
285
const link = document.createElement('a');
286
link.href = href;
287
openLink(link, { metaKey: false, ctrlKey: false, altKey: false, shiftKey: false });
288
}
289
}}
290
>
291
<h3>{title}</h3>
292
<p>{description}</p>
293
</div>
294
);
295
}
296
297
// Router-aware link component
298
function RouterLink({ href, children, ...props }) {
299
const linkProps = useLinkProps({ href, ...props });
300
const router = useRouter();
301
302
return (
303
<a
304
{...linkProps}
305
onClick={(e) => {
306
const modifiers = {
307
metaKey: e.metaKey,
308
ctrlKey: e.ctrlKey,
309
altKey: e.altKey,
310
shiftKey: e.shiftKey
311
};
312
313
if (shouldClientNavigate(e.currentTarget, modifiers)) {
314
e.preventDefault();
315
if (router.isNative) {
316
window.location.href = href;
317
} else {
318
// Use router navigation
319
router.open(e.currentTarget, modifiers);
320
}
321
}
322
}}
323
>
324
{children}
325
</a>
326
);
327
}
328
```
329
330
### Advanced Navigation Patterns
331
332
Complex navigation scenarios with conditional routing and state management:
333
334
```typescript
335
import {
336
useRouter,
337
shouldClientNavigate,
338
useLinkProps,
339
useSyntheticLinkProps
340
} from "@react-aria/utils";
341
342
function AdvancedNavigation() {
343
const router = useRouter();
344
const [isNavigating, setIsNavigating] = useState(false);
345
346
const handleNavigation = useCallback(async (href: string, modifiers: Modifiers) => {
347
const link = document.createElement('a');
348
link.href = href;
349
350
if (shouldClientNavigate(link, modifiers)) {
351
setIsNavigating(true);
352
353
try {
354
// Perform client-side navigation with loading state
355
await router.navigate(href);
356
} finally {
357
setIsNavigating(false);
358
}
359
} else {
360
// Use browser navigation
361
openLink(link, modifiers, true);
362
}
363
}, [router]);
364
365
return (
366
<nav>
367
<NavigationItem
368
href="/dashboard"
369
onClick={handleNavigation}
370
isLoading={isNavigating}
371
>
372
Dashboard
373
</NavigationItem>
374
</nav>
375
);
376
}
377
378
// Context menu with link actions
379
function ContextMenu({ href, onClose }) {
380
const menuActions = [
381
{
382
label: 'Open',
383
action: () => {
384
const link = document.createElement('a');
385
link.href = href;
386
openLink(link, { metaKey: false, ctrlKey: false, altKey: false, shiftKey: false });
387
onClose();
388
}
389
},
390
{
391
label: 'Open in New Tab',
392
action: () => {
393
const link = document.createElement('a');
394
link.href = href;
395
openLink(link, { metaKey: true, ctrlKey: false, altKey: false, shiftKey: false });
396
onClose();
397
}
398
},
399
{
400
label: 'Copy Link',
401
action: () => {
402
navigator.clipboard.writeText(href);
403
onClose();
404
}
405
}
406
];
407
408
return (
409
<ul role="menu">
410
{menuActions.map(action => (
411
<li key={action.label}>
412
<button onClick={action.action}>
413
{action.label}
414
</button>
415
</li>
416
))}
417
</ul>
418
);
419
}
420
```
421
422
## Types
423
424
```typescript { .api }
425
interface DOMProps {
426
id?: string;
427
}
428
429
interface LinkDOMProps extends DOMProps {
430
href?: string;
431
target?: string;
432
rel?: string;
433
download?: boolean | string;
434
ping?: string;
435
referrerPolicy?: string;
436
}
437
438
interface Modifiers {
439
metaKey: boolean;
440
ctrlKey: boolean;
441
altKey: boolean;
442
shiftKey: boolean;
443
}
444
445
interface Router {
446
isNative: boolean;
447
open: (target: HTMLAnchorElement, modifiers: Modifiers, setOpening?: boolean) => void;
448
useHref?: (href: string) => string;
449
}
450
```