A file-based routing library for React Native and web applications.
GitHub
npm
expo-router
is a routing library for React Native and web apps. It enables navigation management using a file-based routing system and provides native navigation components and is built on top of React Navigation.
-Â
npx expo install expo-router
If you are using the default template to create a new project, expo-router
config plugin is automatically configured in the app config automatically.
{
"expo": {
"plugins": ["expo-router"]
}
}
Find more information and guides about using expo-router
in Expo Router section.
import { Stack, Tabs, Link } from 'expo-router';
Link
Type: React.Element<PropsWithChildren<LinkProps<T>>>
Component that renders a link using href
to another route.
By default, it accepts children and wraps them in a <Text>
component.
Uses an anchor tag (<a>
) on web and performs a client-side navigation to preserve
the state of the website and navigate faster. The web-only attributes such as target
,
rel
, and download
are supported and passed to the anchor tag on web. See
WebAnchorProps
for more details.
Note: Client-side navigation works with both single-page apps, and static-rendering.
Example
import { Link } from 'expo-router';
import { View } from 'react-native';
export default function Route() {
return (
<View>
<Link href="/about">About</Link>
</View>
);
}
asChild
boolean
Used to customize the Link
component. It will forward all props to the
first child of the Link
. Note that the child component must accept
onPress
or onClick
props. The href
and role
are also
passed to the child.
Example
import { Link } from 'expo-router';
import { Pressable, Text } from 'react-native';
export default function Route() {
return (
<View>
<Link href="/home" asChild>
<Pressable>
<Text>Home</Text>
</Pressable>
</Link>
</View>
);
}
className
string
On native, this can be used with CSS interop tools like Nativewind.
On web, this sets the HTML class
directly.
href
Href<T>
The path of the route to navigate to. It can either be:
/profile/settings
or a relative path like ../settings
.pathname
and optional params
. 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.Example
import { Link } from 'expo-router';
import { View } from 'react-native';
export default function Route() {
return (
<View>
<Link href="/about">About</Link>
<Link
href={{
pathname: '/user/[id]',
params: { id: 'bacon' }
}}>
View user
</Link>
</View>
);
}
onPress
(e: MouseEvent<HTMLAnchorElement, MouseEvent> | GestureResponderEvent) => void
This function is called on press. Text intrinsically supports press handling with a default highlight state (which can be disabled with suppressHighlighting).
push
boolean
Always pushes a new route, and never pops or replaces to existing route. You can push the current route multiple times or with new parameters.
Example
import { Link } from 'expo-router';
import { View } from 'react-native';
export default function Route() {
return (
<View>
<Link push href="/feed">Login</Link>
</View>
);
}
relativeToDirectory
boolean
Relative URL references are either relative to the directory or the document. By default, relative paths are relative to the document.
replace
boolean
Removes the current route from the history and replace it with the specified URL. This is useful for redirects.
Example
import { Link } from 'expo-router';
import { View } from 'react-native';
export default function Route() {
return (
<View>
<Link replace href="/feed">Login</Link>
</View>
);
}
withAnchor
boolean
Replaces the initial screen with the current route.
Omit<TextProps, 'href'>
WebAnchorProps
Slot
Type: React.Element<Omit<NavigatorProps<any>, 'children'>>
Renders the currently selected content.
There are actually two different implementations of <Slot/>
:
_layout
as the Navigator
Navigator
as the contentSince a custom Navigator
will set the NavigatorContext.contextKey
to
the current _layout
, you can use this to determine if you are inside
a custom navigator or not.
useFocusEffect(effect, do_not_pass_a_second_prop)
Parameter | Type | Description |
---|---|---|
effect | EffectCallback | Memoized callback containing the effect, should optionally return a cleanup function. |
do_not_pass_a_second_prop (optional) | undefined | - |
Hook to run an effect whenever a route is focused. Similar to
React.useEffect
.
This can be used to perform side-effects such as fetching data or subscribing to events.
The passed callback should be wrapped in React.useCallback
to avoid running the effect too often.
void
Example
import { useFocusEffect } from 'expo-router';
import { useCallback } from 'react';
export default function Route() {
useFocusEffect(
// Callback should be wrapped in `React.useCallback` to avoid running the effect too often.
useCallback(() => {
// Invoked whenever the route is focused.
console.log('Hello, I'm focused!');
// Return function is invoked whenever the route gets out of focus.
return () => {
console.log('This route is now unfocused.');
};
}, []);
);
return </>;
}
useGlobalSearchParams()
Returns URL parameters for globally selected route, including dynamic path segments. This function updates even when the route is not focused. Useful for analytics or other background operations that don't draw to the screen.
Route URL example: acme://profile/baconbrix?extra=info
.
When querying search params in a stack, opt-towards using
useLocalSearchParams
because it will only update when the route is focused.
Note: For usage information, see Local versus global search parameters.
RouteParams<TRoute, TParams>
Example
import { Text } from 'react-native';
import { useGlobalSearchParams } from 'expo-router';
export default function Route() {
// user=baconbrix & extra=info
const { user, extra } = useGlobalSearchParams();
return <Text>User: {user}</Text>;
}
useLocalSearchParams()
Returns the URL parameters for the contextually focused route. Useful for stacks where you may push a new screen that changes the query parameters. For dynamic routes, both the route parameters and the search parameters are returned.
Route URL example: acme://profile/baconbrix?extra=info
.
To observe updates even when the invoking route is not focused, use useGlobalSearchParams
.
Note: For usage information, see Local versus global search parameters.
RouteParams<TRoute, TParams>
Example
import { Text } from 'react-native';
import { useLocalSearchParams } from 'expo-router';
export default function Route() {
// user=baconbrix & extra=info
const { user, extra } = useLocalSearchParams();
return <Text>User: {user}</Text>;
}
useNavigation(parent)
Parameter | Type | Description |
---|---|---|
parent (optional) | string | Provide an absolute path such as |
Returns the underlying React Navigation navigation
prop
to imperatively access layout-specific functionality like navigation.openDrawer()
in a
Drawer layout.
T
The navigation object for the current route.
See: React Navigation documentation on navigation dependent functions for more information.
Example
import { useNavigation } from 'expo-router';
export default function Route() {
// Access the current navigation object for the current route.
const navigation = useNavigation();
return (
<View>
<Text onPress={() => {
// Open the drawer view.
navigation.openDrawer();
}}>
Open Drawer
</Text>
</View>
);
}
When using nested layouts, you can access higher-order layouts by passing a secondary argument denoting the layout route.
For example, /menu/_layout.tsx
is nested inside /app/orders/
, you can use useNavigation('/orders/menu/')
.
Example
import { useNavigation } from 'expo-router';
export default function MenuRoute() {
const rootLayout = useNavigation('/');
const ordersLayout = useNavigation('/orders');
// Same as the default results of `useNavigation()` when invoked in this route.
const parentLayout = useNavigation('/orders/menu');
}
If you attempt to access a layout that doesn't exist, an error such as
Could not find parent navigation with route "/non-existent"
is thrown.
useNavigationContainerRef()
NavigationContainerRefWithCurrent<RootParamList>
The root <NavigationContainer />
ref for the app. The ref.current
may be null
if the <NavigationContainer />
hasn't mounted yet.
usePathname()
Returns the currently selected route location without search parameters. For example, /acme?foo=bar
returns /acme
.
Segments will be normalized. For example, /[id]?id=normal
becomes /normal
.
string
Example
import { Text } from 'react-native';
import { useSegments } from 'expo-router';
export default function Route() {
// segments = ["profile", "[user]"]
const segments = useSegments();
return <Text>Hello</Text>;
}
Deprecated Use
useNavigationContainerRef
instead, which returns a Reactref
.
useRootNavigation()
null | NavigationContainerRef<RootParamList>
useRootNavigationState()
Returns the navigation state of the navigator which contains the current screen.
any
Example
import { useRootNavigationState } from 'expo-router';
export default function Route() {
const { routes } = useRootNavigationState();
return <Text>{routes[0].name}</Text>;
}
useRouter()
Returns the Router object for imperative navigation.
Example
import { useRouter } from 'expo-router';
import { Text } from 'react-native';
export default function Route() {
const router = useRouter();
return (
<Text onPress={() => router.push('/home')}>Go Home</Text>
);
}
useSegments()
Returns a list of selected file segments for the currently selected route. Segments are not normalized,
so they will be the same as the file path. For example, /[id]?id=normal
becomes ["[id]"]
.
Example
import { Text } from 'react-native';
import { useSegments } from 'expo-router';
export default function Route() {
// segments = ["profile", "[user]"]
const segments = useSegments();
return <Text>Hello</Text>;
}
useSegments
can be typed using an abstract. Consider the following file structure:
- app
- [user]
- index.tsx
- followers.tsx
- settings.tsx
This can be strictly typed using the following abstract with useSegments
hook:
const [first, second] = useSegments<['settings'] | ['[user]'] | ['[user]', 'followers']>()
Redirect(namedParameters)
Parameter | Type |
---|---|
namedParameters | {
href: Href
} |
Redirects to the href
as soon as the component is mounted.
null
Example
import { View, Text } from 'react-native';
import { Redirect } from 'expo-router';
export default function Page() {
const { user } = useAuth();
if (!user) {
return <Redirect href="/login" />;
}
return (
<View>
<Text>Welcome Back!</Text>
</View>
);
}
withLayoutContext(Nav, processor)
Parameter | Type |
---|---|
Nav | T |
processor (optional) | (options: ScreenProps[]) => ScreenProps[] |
Returns a navigator that automatically injects matched routes and renders nothing when there are no children.
Return type with children
prop optional.
Component<PropsWithoutRef<PickPartial<ComponentProps<T>, 'children'>>> & {
Screen: (props: ScreenProps<TOptions, TState, TEventMap>) => null
}
EffectCallback()
Memoized callback containing the effect, should optionally return a cleanup function.
undefined | void | () => void
Href
Type: GeneratedHref<T>
The main routing type for Expo Router. It includes all available routes with strongly typed parameters. It can either be:
/profile/settings
or a relative path like ../settings
.pathname
and optional params
. 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.It can also accept an optional <T>
parameter to correctly type dynamic routes string.
For example, without the generic the route /folder/[slug]
will be typed as /folder/${string}
,
which is incorrect as /folder/apple/orange
would be valid. However, by passing desired
route as a generic Href<'/folder/apple'>
, it will validate against this edge case.
NativeIntent
Created by using a special file called +native-intent.tsx
at the top-level of your
project's app directory. It exports redirectSystemPath
or legacy_subscribe
functions,
both methods designed to handle URL/path processing.
Useful for re-writing URLs to correctly target a route when unique/referred URLs are incoming from third-party providers or stale URLs from previous versions.
See: For more information on how to use
NativeIntent
, see Customizing links.
Name | Type | Description |
---|---|---|
legacy_subscribe (optional) | (listener: (url: string) => void) => undefined | void | () => void |
Useful as an alternative API when a third-party provider doesn't support Expo Router
but has support for React Navigation via Using this API is not recommended for newer projects or integrations since it is incompatible with Server Side Routing and Static Rendering, and can become challenging to manage while offline or in a low network environment. |
redirectSystemPath (optional) | (event: {
initial: boolean,
path: string
}) => Promise<string> | string | A special method used to process URLs in native apps. When invoked, it receives an
It's return value should either be a
|
PickPartial
Literal Type: multiple types
The list of input keys will become optional, everything else will remain the same.
ResultState
Type: PartialState<NavigationState>
extended by:
Name | Type | Description |
---|---|---|
state (optional) | ResultState | - |
Router
Returns router
object for imperative navigation API.
Example
import { router } from 'expo-router';
import { Text } from 'react-native';
export default function Route() {
return (
<Text onPress={() => router.push('/home')}>Go Home</Text>
);
}
Name | Type | Description |
---|---|---|
back | () => void | Goes back in the navigation history. |
canDismiss | () => boolean | Checks if it is possible to dismiss the current screen. Returns |
canGoBack | () => boolean | Navigates to a route in the navigator's history if it supports invoking the |
dismiss | (count: number) => void | Navigates to the a stack lower than the current screen using the provided count if possible, otherwise 1. If the current screen is the only route, it will dismiss the entire stack. |
dismissAll | () => void | Returns to the first screen in the closest stack. This is similar to popToTop stack action. |
navigate | (href: Href<T>, options: NavigationOptions) => void | Navigates to the provided |
push | (href: Href<T>, options: NavigationOptions) => void | Navigates to the provided |
replace | (href: Href<T>, options: NavigationOptions) => void | Navigates to route without appending to the history. Can be used with
|
setParams | (params: Partial<RouteParamInput<T>>) => void | Updates the current route's query params. |
ScreenProps
Name | Type | Description |
---|---|---|
getId (optional) | ({ params }: {
params: Record<string, any>
}) => string | undefined | - |
initialParams (optional) | Record<string, any> | - |
listeners (optional) | ScreenListeners<TState, TEventMap> | (prop: {
navigation: any,
route: RouteProp<ParamListBase, string>
}) => ScreenListeners<TState, TEventMap> | - |
name (optional) | string | Name is required when used inside a Layout component. |
options (optional) | TOptions | (prop: {
navigation: any,
route: RouteProp<ParamListBase, string>
}) => TOptions | - |
redirect (optional) | boolean | Redirect to the nearest sibling route.
If all children are |
WebAnchorProps
Name | Type | Description |
---|---|---|
download (optional) | string | Specifies that the The value of the Example
|
rel (optional) | string | Specifies the relationship between the Common values:
The This property is passed to the underlying anchor ( Example
|
target (optional) | '_self' | '_blank' | '_parent' | '_top' | string & object | Specifies where to open the
This property is passed to the underlying anchor ( Default: '_self' Example
|