
Universal Link
component
If you import the Link
component from @green-stack/navigation
, it will automatically use the correct navigation system for the platform you are on.
import { Link } from '@green-stack/navigation'
However, you can also import it from @app/primitives
to apply tailwind styles:
import { Link } from '@app/primitives'
You can use the href
prop to navigate to a new page:
<Link
className="text-link p-2 rounded"
href="/examples/[slug]"
>
See example
</Link>
UniversalLinkProps
Property | Type | Description |
---|---|---|
children | React.ReactNode | The content to be rendered inside the link. |
href | string | HREF | The path to route to on web or mobile. String only. Hints for internal routes provided through codegen. |
style | Style prop: https://reactnative.dev/docs/text#style | |
className | string | Nativewind classNames should be applied to either the parent or children of Link. Ideally, create or use a TextLink component instead. |
replace | boolean | Should replace the current route without adding to the history - Default: false. |
onPress | Extra handler that fires when the link is pressed. | |
target | Specifies where to display the linked URL. | |
asChild | boolean | Mobile only - Forward props to child component. Useful for custom buttons - Default: false. |
push | boolean | Mobile only - Should push the current route, always adding to the history - Default: true. |
testID | string | undefined | Mobile only - Used to locate this view in end-to-end tests. |
nativeID | string | undefined | Mobile only - Used to reference react managed views from native code. @deprecated use id instead. |
id | string | undefined | Mobile only - Used to reference react managed views from native code. |
allowFontScaling | Mobile only - Specifies whether fonts should scale to respect Text Size accessibility settings. | |
numberOfLines | Mobile only - Specifies the maximum number of lines to use for rendering text. | |
maxFontSizeMultiplier | Mobile only - Specifies the maximum scale factor for text. | |
suppressHighlighting | Mobile only - When true, no visual change is made when text is pressed down. | |
scroll | boolean | Web only - Whether to override the default scroll behavior - Default: false. |
shallow | boolean | Web only - Update the path of the current page without rerunning getStaticProps, getServerSideProps or getInitialProps - Default: false. |
passHref | boolean | Web only - Forces Link to send the href property to its child - Default: false. |
prefetch | boolean | Web only - Prefetch the page in the background. Any <Link /> that is in the viewport (initially or through scroll) will be preloaded. Prefetch can be disabled by passing prefetch={false} . When prefetch is set to false , prefetching will still occur on hover. Pages using Static Generation will preload JSON files with the data for faster page transitions. Prefetching is only enabled in production. - Default: true |
locale | string | false | Web only - The active locale is automatically prepended. locale allows for providing a different locale. When false href has to include the locale as the default behavior is disabled. |
as | Url | undefined | Web only - Optional decorator for the path that will be shown in the browser URL bar. |
Here’s what that would look like in TypeScript:
type UniversalLinkProps<HREF extends KnownRoutes = KnownRoutes> = {
children: React.ReactNode;
/** Universal - The path to route to on web or mobile. String only. */
href: HREF;
/** Universal - Style prop: https://reactnative.dev/docs/text#style */
style?: StyleProp<TextStyle>;
/** -!- Nativewind classNames should be applied to either the parent or children of Link. Ideally, create or use a TextLink component instead */
className?: string; // never;
/** Universal - Should replace the current route without adding to the history - Default: false. */
replace?: boolean;
/** Universal - Extra handler that fires when the link is pressed. */
onPress?: ((e: MouseEvent<HTMLAnchorElement> | GestureResponderEvent) => void) | null | undefined;
/** Universal - */
target?: "_self" | "_blank" | "_parent" | "_top" | undefined;
// - Expo -
/** Mobile only - Forward props to child component. Useful for custom buttons - Default: false */
asChild?: boolean;
/** Mobile only - Should push the current route, always adding to the history - Default: true */
push?: boolean;
/** Mobile only - Used to locate this view in end-to-end tests. */
testID?: string | undefined;
/** Mobile only - Used to reference react managed views from native code. @deprecated use `id` instead. */
nativeID?: string | undefined;
id?: string | undefined;
allowFontScaling?: boolean | undefined;
numberOfLines?: number | undefined;
maxFontSizeMultiplier?: number | null | undefined;
suppressHighlighting?: boolean | undefined;
// - Next -
/** Web only - Whether to override the default scroll behavior - Default: false */
scroll?: boolean;
/** Web only - Update the path of the current page without rerunning getStaticProps, getServerSideProps or getInitialProps - Default: false */
shallow?: boolean;
/** Web only - Forces `Link` to send the `href` property to its child - Default: false */
passHref?: boolean;
/** Web only - Prefetch the page in the background. Any `<Link />` that is in the viewport (initially or through scroll) will be preloaded. Prefetch can be disabled by passing `prefetch={false}`. When `prefetch` is set to `false`, prefetching will still occur on hover. Pages using [Static Generation](/docs/basic-features/data-fetching/get-static-props.md) will preload `JSON` files with the data for faster page transitions. Prefetching is only enabled in production. - Defaultvalue: true */
prefetch?: boolean;
/** Web only - The active locale is automatically prepended. `locale` allows for providing a different locale. When `false` `href` has to include the locale as the default behavior is disabled. */
locale?: string | false;
/** Web only - Optional decorator for the path that will be shown in the browser URL bar. Before Next.js 9.5.3 this was used for dynamic routes, check our [previous docs](https://github.com/vercel/next.js/blob/v9.5.2/docs/api-reference/next/link.md#dynamic-routes) to see how it worked. Note: when this path differs from the one provided in `href` the previous `href`/`as` behavior is used as shown in the [previous docs](https://github.com/vercel/next.js/blob/v9.5.2/docs/api-reference/next/link.md#dynamic-routes). */
as?: Url | undefined;
}
React Portability Patterns
Each environment has it’s own optimized Link component. This is why there are also versions specifically for each of those environments:
- Link.expo.tsx
- Link.next.tsx
- Link.tsx
- Link.types.ts
Link.next.tsx
is optimized for the Next.js app router.Link.expo.tsx
is optimized for Expo Router.Link.types.ts
ensures both implementations are compatible with the same interface, allowing you to use the sameLink
component across both Expo and Next.js environments.
The main Link.tsx
retrieves whichever implementation was provided as contextLink
to the <UniversalAppProviders>
component, which is further passed to <CoreContext.Provider/>
:
import { Link as ExpoLink } from '@green-stack/navigation/Link.expo'
// ... Later ...
<UniversalAppProviders
contextLink={ExpoLink}
>
...
</UniversalAppProviders>
import { Link as NextLink } from '@green-stack/navigation/Link.next'
// ... Later ...
<UniversalAppProviders
contextLink={NextLink}
>
...
</UniversalAppProviders>
Why this pattern?
The ‘React Portability Patterns’ used here are designed to ensure that you can easily reuse optimized versions of components across different flavours of writing React.
On the one hand, that means it’s already set up to work with both Expo and Next.js in an optimal way.
But, you can actually add your own implementations for other environments, without having to refactor the code that uses the Link
component.
Supporting more environments
Just add your own Link.<environment>.tsx
file that respects the shared types, and then pass it to the <UniversalAppProviders>
component as contextLink
.