or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

deep-linking.mdindex.mdlink-components.mdnavigation-container.mdnavigation-hooks.mdserver-side-rendering.mdstatic-navigation.mdtheming.md

deep-linking.mddocs/

0

# Deep Linking

1

2

Deep linking enables navigation to specific screens in your app using URLs. React Navigation provides comprehensive URL-based navigation with path matching, prefixes, and state synchronization.

3

4

## Capabilities

5

6

### Linking Options Configuration

7

8

Configure deep linking behavior through the NavigationContainer's linking prop.

9

10

```typescript { .api }

11

interface LinkingOptions<ParamList extends {}> {

12

/** Whether deep link handling should be enabled. Defaults to true when linking options are provided */

13

enabled?: boolean;

14

/** URL prefixes to match against. Stripped from URLs before parsing */

15

prefixes: string[];

16

/** Optional function to filter which URLs should be handled */

17

filter?: (url: string) => boolean;

18

/** Path configuration for mapping URLs to navigation state */

19

config?: {

20

/** Root path for the entire navigation tree */

21

path?: string;

22

/** Screen path configurations */

23

screens: PathConfigMap<ParamList>;

24

/** Name of the initial route for the root navigator */

25

initialRouteName?: keyof ParamList;

26

};

27

/** Custom function to get the initial URL. Defaults to Linking.getInitialURL() */

28

getInitialURL?: () => string | null | undefined | Promise<string | null | undefined>;

29

/** Custom function to subscribe to URL updates */

30

subscribe?: (listener: (url: string) => void) => undefined | void | (() => void);

31

/** Custom function to parse URL to navigation state */

32

getStateFromPath?: typeof getStateFromPath;

33

/** Custom function to convert navigation state to URL */

34

getPathFromState?: typeof getPathFromState;

35

/** Custom function to convert navigation state to action */

36

getActionFromState?: typeof getActionFromState;

37

}

38

39

type PathConfigMap<ParamList> = {

40

[RouteName in keyof ParamList]: string | PathConfig<ParamList[RouteName]>;

41

};

42

43

interface PathConfig<ParamList> {

44

path?: string;

45

exact?: boolean;

46

screens?: PathConfigMap<ParamList>;

47

initialRouteName?: keyof ParamList;

48

parse?: { [Param in keyof ParamList]?: (value: string) => ParamList[Param] };

49

stringify?: { [Param in keyof ParamList]?: (value: ParamList[Param]) => string };

50

}

51

```

52

53

**Usage Examples:**

54

55

```typescript

56

import { NavigationContainer } from '@react-navigation/native';

57

58

// Basic deep linking setup

59

const linking = {

60

prefixes: ['myapp://'],

61

config: {

62

screens: {

63

Home: 'home',

64

Profile: 'profile/:id',

65

Settings: 'settings',

66

},

67

},

68

};

69

70

function App() {

71

return (

72

<NavigationContainer linking={linking}>

73

{/* Your navigators */}

74

</NavigationContainer>

75

);

76

}

77

78

// Advanced configuration with nested navigators

79

const advancedLinking = {

80

prefixes: ['myapp://', 'https://myapp.com'],

81

config: {

82

screens: {

83

Auth: {

84

screens: {

85

Login: 'login',

86

Register: 'register',

87

},

88

},

89

Main: {

90

screens: {

91

Home: 'home',

92

Profile: {

93

path: 'profile/:id',

94

parse: {

95

id: (id: string) => parseInt(id, 10),

96

},

97

},

98

Settings: {

99

path: 'settings',

100

screens: {

101

Account: 'account',

102

Privacy: 'privacy',

103

},

104

},

105

},

106

},

107

},

108

},

109

};

110

111

// With URL filtering

112

const filteredLinking = {

113

prefixes: ['myapp://'],

114

filter: (url: string) => !url.includes('oauth-callback'),

115

config: {

116

screens: {

117

Home: 'home',

118

Profile: 'profile/:id',

119

},

120

},

121

};

122

```

123

124

### URL Prefixes

125

126

Define which URL schemes and hosts your app should handle.

127

128

```typescript { .api }

129

interface LinkingOptions<ParamList> {

130

/**

131

* The prefixes are stripped from the URL before parsing them.

132

* Usually they are the scheme + host (e.g. myapp://chat?user=jane)

133

* This is not supported on Web.

134

*/

135

prefixes: string[];

136

}

137

```

138

139

**Usage Examples:**

140

141

```typescript

142

// App-specific scheme

143

const linking = {

144

prefixes: ['myapp://'],

145

// myapp://profile/123 -> profile/123

146

};

147

148

// Universal links

149

const universalLinking = {

150

prefixes: ['https://example.com'],

151

// https://example.com/profile/123 -> profile/123

152

};

153

154

// Multiple prefixes with wildcards

155

const multiPrefixLinking = {

156

prefixes: [

157

'myapp://',

158

'https://example.com',

159

'https://*.example.com', // Matches any subdomain

160

],

161

};

162

163

// Development and production

164

const environmentLinking = {

165

prefixes: [

166

'myapp://',

167

__DEV__

168

? 'https://dev.example.com'

169

: 'https://example.com',

170

],

171

};

172

```

173

174

### Path Configuration

175

176

Map URL paths to navigation screens with parameter parsing.

177

178

```typescript { .api }

179

interface PathConfig<ParamList> {

180

/** Path pattern to match (e.g., 'profile/:id') */

181

path?: string;

182

/** Whether the path should match exactly */

183

exact?: boolean;

184

/** Nested screen configurations */

185

screens?: PathConfigMap<ParamList>;

186

/** Initial route name for nested navigators */

187

initialRouteName?: keyof ParamList;

188

/** Functions to parse URL parameters */

189

parse?: { [Param in keyof ParamList]?: (value: string) => ParamList[Param] };

190

/** Functions to stringify parameters for URL generation */

191

stringify?: { [Param in keyof ParamList]?: (value: ParamList[Param]) => string };

192

}

193

```

194

195

**Usage Examples:**

196

197

```typescript

198

// Simple path mapping

199

const config = {

200

screens: {

201

Home: 'home',

202

About: 'about',

203

Contact: 'contact',

204

},

205

};

206

207

// Paths with parameters

208

const paramsConfig = {

209

screens: {

210

Profile: 'profile/:id',

211

Article: 'article/:slug',

212

Category: 'category/:name/page/:page',

213

},

214

};

215

216

// Parameter parsing and validation

217

const parsedConfig = {

218

screens: {

219

Profile: {

220

path: 'profile/:id',

221

parse: {

222

id: (id: string) => {

223

const parsed = parseInt(id, 10);

224

return isNaN(parsed) ? 0 : parsed;

225

},

226

},

227

},

228

Search: {

229

path: 'search',

230

parse: {

231

q: (query: string) => decodeURIComponent(query),

232

page: (page: string) => Math.max(1, parseInt(page, 10)),

233

},

234

},

235

},

236

};

237

238

// Nested navigator configuration

239

const nestedConfig = {

240

screens: {

241

Home: 'home',

242

Shop: {

243

path: 'shop',

244

screens: {

245

ProductList: 'products',

246

ProductDetail: 'product/:id',

247

Cart: 'cart',

248

Checkout: {

249

path: 'checkout',

250

screens: {

251

Shipping: 'shipping',

252

Payment: 'payment',

253

Confirmation: 'confirmation',

254

},

255

},

256

},

257

},

258

},

259

};

260

```

261

262

### URL Filtering

263

264

Control which URLs should be handled by your navigation system.

265

266

```typescript { .api }

267

interface LinkingOptions<ParamList> {

268

/**

269

* Optional function which takes an incoming URL and returns a boolean

270

* indicating whether React Navigation should handle it.

271

* This can be used to disable deep linking for specific URLs.

272

*/

273

filter?: (url: string) => boolean;

274

}

275

```

276

277

**Usage Examples:**

278

279

```typescript

280

// Filter out authentication callbacks

281

const authFilterLinking = {

282

prefixes: ['myapp://'],

283

filter: (url: string) => !url.includes('oauth-callback'),

284

config: {

285

screens: {

286

Home: 'home',

287

Profile: 'profile/:id',

288

},

289

},

290

};

291

292

// Filter based on URL patterns

293

const patternFilterLinking = {

294

prefixes: ['myapp://'],

295

filter: (url: string) => {

296

// Don't handle admin URLs

297

if (url.includes('/admin/')) return false;

298

// Don't handle external redirects

299

if (url.includes('redirect=')) return false;

300

// Handle everything else

301

return true;

302

},

303

};

304

```

305

306

### Custom URL Handling

307

308

Implement custom logic for URL processing and state management.

309

310

```typescript { .api }

311

interface LinkingOptions<ParamList> {

312

/** Custom function to get the initial URL used for linking */

313

getInitialURL?: () => string | null | undefined | Promise<string | null | undefined>;

314

/** Custom function to subscribe to URL updates */

315

subscribe?: (listener: (url: string) => void) => undefined | void | (() => void);

316

/** Custom function to parse URL to navigation state (advanced) */

317

getStateFromPath?: typeof getStateFromPath;

318

/** Custom function to convert state to URL (advanced) */

319

getPathFromState?: typeof getPathFromState;

320

/** Custom function to convert state to action (advanced) */

321

getActionFromState?: typeof getActionFromState;

322

}

323

```

324

325

**Usage Examples:**

326

327

```typescript

328

import { Linking } from 'react-native';

329

330

// Custom initial URL handling

331

const customInitialURL = {

332

prefixes: ['myapp://'],

333

getInitialURL: async () => {

334

// Check if app was opened from a deep link

335

const url = await Linking.getInitialURL();

336

337

// Custom logic for handling the initial URL

338

if (url?.includes('special-link')) {

339

// Transform or validate the URL

340

return url.replace('special-link', 'normal-link');

341

}

342

343

return url;

344

},

345

};

346

347

// Custom URL subscription

348

const customSubscription = {

349

prefixes: ['myapp://'],

350

subscribe: (listener: (url: string) => void) => {

351

// Custom URL change handling

352

const onReceiveURL = ({ url }: { url: string }) => {

353

// Apply custom transformations or filtering

354

if (url.includes('valid-prefix')) {

355

listener(url);

356

}

357

};

358

359

const subscription = Linking.addEventListener('url', onReceiveURL);

360

361

return () => subscription?.remove();

362

},

363

};

364

365

// Custom state parsing

366

const customStateParsing = {

367

prefixes: ['myapp://'],

368

getStateFromPath: (path: string, config: any) => {

369

// Custom logic to convert path to navigation state

370

if (path.startsWith('/legacy/')) {

371

// Handle legacy URL format

372

const newPath = path.replace('/legacy/', '/');

373

return getStateFromPath(newPath, config);

374

}

375

376

// Use default parsing for other paths

377

return getStateFromPath(path, config);

378

},

379

};

380

```

381

382

### Error Handling

383

384

Handle cases where deep links cannot be processed or lead to invalid states.

385

386

```typescript { .api }

387

// Invalid URLs that don't match any configured path will be ignored

388

// Use NavigationContainer's onUnhandledAction prop to handle edge cases

389

390

function App() {

391

const handleUnhandledAction = (action: NavigationAction) => {

392

console.warn('Unhandled navigation action:', action);

393

// Custom error handling or fallback navigation

394

};

395

396

return (

397

<NavigationContainer

398

linking={linking}

399

onUnhandledAction={handleUnhandledAction}

400

>

401

{/* Your navigators */}

402

</NavigationContainer>

403

);

404

}

405

```