Skip to main content

Linking

Use the <Link /> component to navigate between pages. This is conceptually similar to the <a> element in HTML.

import { Link } from "expo-router";

export default function Page() {
return (
<View>
<Link href="/">Home</Link>
</View>
);
}
  • href accepts relative paths like ../settings or full paths like /profile/settings. Relative paths are useful for shared routes.
  • href can also accept an object like { pathname: 'profile', params: { id: '123' } } to navigate to dynamic routes.
  • Use the replace prop to replace the current route in the history instead of pushing a new route.

The Link component renders a <Text> component by default. You can customize the component by passing asChild which will forward all props to the first child of the Link component. The child component must support the onPress and onClick props, href and accessibilityRole will also be passed down.

import { Pressable, Text } from "react-native";
import { Link } from "expo-router";

function Home() {
return (
<Link href="/other" asChild>
<Pressable>{({ hovered, pressed }) => <Text>Home</Text>}</Pressable>
</Link>
);
}

useRouter

For more advanced use cases, you can use the imperative useRouter() hook to navigate imperatively.

import { View, Text } from "react-native";
import { useRouter } from "expo-router";

export default function Page() {
const router = useRouter();

return (
<View>
<Text
onPress={() => {
router.push("/profile/settings");
}}
>
Settings
</Text>
</View>
);
}
  • push: (href: Href) => void Navigate to a route. You can provide a full path like /profile/settings or a relative path like ../settings. Navigate to dynamic routes by passing an object like { pathname: 'profile', params: { id: '123' } }.
  • replace: (href: Href) => void Same API as push but replaces the current route in the history instead of pushing a new one. This is useful for redirects.
  • back: () => void Navigate back to previous route.
  • setParams: (params: Record<string, string>) => void Update the query params for the currently selected route.

Href type

The Href type is a union of the following types:

  • string: A full path like /profile/settings or a relative path like ../settings.
  • object: An object with a pathname and optional params object. The pathname can be a full path like /profile/settings or a relative path like ../settings. The params can be an object of key/value pairs.

usePathname

Returns the currently selected route location without search parameters. e.g. /acme?foo=bar -> /acme. Segments will be normalized: /[id]?id=normal -> /normal

/profile/baconbrix?extra=info

app/profile/[user].tsx
import { Text } from "react-native";
import { usePathname } from "expo-router";

export default function Route() {
const pathname = usePathname();
// pathname = "/profile/baconbrix"
return <Text>User: {user}</Text>;
}

useLocalSearchParams

Returns the URL search parameters for the contextually selected route. e.g. /acme?foo=bar -> { foo: "bar" }. This is useful for stacks where the previous screen is still mounted.

app/
_layout.js
[first]/home.tsx
[second]/shop.tsx

When /abc/home pushes /123/shop, useGlobalSearchParams would return { first: undefined, second: '123' } on /app/[first]/home.tsx because the global URL has changed. However, you may want the params to remain { first: 'abc' } to reflect the context of the screen. In this case, you can use useLocalSearchParams to ensure the params { first: 'abc' } are still returned in /app/[first]/home.tsx.

/profile/baconbrix?extra=info

app/profile/[user].tsx
import { Text } from "react-native";
import { useLocalSearchParams } from "expo-router";

export default function Route() {
const { user, extra } = useLocalSearchParams();
return <Text>User: {user}</Text>;
}

This function can be typed using an abstract:

app/profile/[user].tsx
import { useLocalSearchParams } from "expo-router";

export default function Route() {
const { user, extra } = useLocalSearchParams<{
user: string;
extra?: string;
}>();
}

useGlobalSearchParams

Returns the URL search parameters for the globally selected route. e.g. /acme?foo=bar -> { foo: "bar" }.

/profile/baconbrix?extra=info

app/profile/[user].tsx
import { Text } from "react-native";
import { useGlobalSearchParams } from "expo-router";

export default function Route() {
const { user, extra } = useGlobalSearchParams();
return <Text>User: {user}</Text>;
}

Given a route at app/profile/[id].tsx if the hook is called while the URL is /profile/123, the results of useGlobalSearchParams would be as follows:

{
id: "123";
}

This function can be typed using an abstract:

app/profile/[user].tsx
import { useGlobalSearchParams } from "expo-router";

export default function Route() {
const { user, extra } = useGlobalSearchParams<{
user: string;
extra?: string;
}>();
}

useSegments

Returns a list of segments for the currently selected route. Segments are not normalized, so they will be the same as the file path. e.g. /[id]?id=normal -> ["[id]"]

app/profile/[user].tsx
import { Text } from "react-native";
import { useSegments } from "expo-router";

export default function Route() {
const segments = useSegments();
// segments = ["profile", "[user]"]
return <Text>Hello</Text>;
}

This function can be typed using an abstract of string arrays:

app/profile/[user].tsx
import { useSegments } from "expo-router";

export default function Route() {
const segments = useSegments<["profile"] | ["profile", "[user]"]>();
}

useNavigation

Access the underlying React Navigation navigation prop to imperatively access layout-specific functionality like navigation.openDrawer() in a Drawer layout. Learn more.

import { useNavigation } from "expo-router";

export default function Route() {
const navigation = useNavigation();
return (
<View>
<Text
onPress={() => {
navigation.openDrawer();
}}
>
Open Drawer
</Text>
</View>
);
}

useSearchParams

This function has been renamed to useGlobalSearchParams. Often, you'll want to use useLocalSearchParams unless you're attempting to observe and report the global state.

Redirect

You can immediately redirect from a particular screen by using the Redirect component:

import { View, Text } from "react-native";
import { Redirect } from "expo-router";

export default function Page() {
// Some logic to determine if the user is logged in.
const { user } = useAuth();

if (!user) {
// Redirect to the login screen if the user is not authenticated.
return <Redirect href="/login" />;
}

return (
<View>
<Text>Welcome Back!</Text>
</View>
);
}

You can also redirect imperatively using the useRouter hook:

import { Text } from "react-native";
import { useRouter, useFocusEffect } from "expo-router";

function MyScreen() {
const router = useRouter();

useFocusEffect(() => {
// Call the replace method to redirect to a new route without adding to the history.
// We do this in a useFocusEffect to ensure the redirect happens every time the screen
// is focused.
router.replace("/profile/settings");
});

return <Text>My Screen</Text>;
}

Testing

On native, you can use the uri-scheme CLI to test opening native links on a device.

For example, if you want to launch the Expo Go app on iOS to the /form-sheet route, you can run:

Replace 192.168.87.39:19000 with the IP address shown when running npx expo start.

npx uri-scheme open exp://192.168.87.39:19000/--/form-sheet --ios

You can also search for links directly in a browser like Safari or Chrome to test deep linking on physical devices. Learn more about testing deep links.

Sitemap

We currently inject a /_sitemap file which provides a list of all routes in the app. This is useful for debugging and development. This screen is only injected during development, and won't be available in production.

We may remove this feature for the official release, but it's useful for now.