In React Native Web, what do href and hrefAttrs render on a View or Text, and why prefer them over Linking.openURL in onPress?
answer
- a real anchor, not a click handler
- download, rel, target
- target gets its underscore added
- middle-click, copy link, crawlers
- web-only props, not React Native core
basics
~20 sIn React Native Web, href on View or Text renders an a element and hrefAttrs adds download, rel and target. A real anchor keeps new-tab gestures, copy link, crawlability and link semantics that onPress with Linking.openURL loses.
solid answer
~40 s`href` is a React Native Web extension on `View` and `Text`: when it is set, the element becomes an `<a href>` instead of a `div`. `hrefAttrs` is read only alongside `href` and copies `download`, `rel` and `target` onto the anchor; a `target` without a leading underscore gets one, so `'blank'` becomes `_blank`, and `null` values are left out. Prefer it to `onPress={() => Linking.openURL(url)}` because a real anchor gives users middle-click and Cmd-click, the context menu's copy link and open in new tab, and a status-bar preview, gives crawlers a link to follow and gives screen readers a link role. React Native Web's `Linking.openURL` just calls `window.open` with `_blank` by default. These props are not part of React Native core, so native builds need their own handling.
code
tsx · 14 linesimport { Linking, Platform, Pressable, Text } from 'react-native';
export function ExternalLink({ url, label }: { url: string; label: string }) {
if (Platform.OS === 'web') {
// react-native-web only: renders <a href target="_blank" rel="noopener">
const webProps = { href: url, hrefAttrs: { target: 'blank', rel: 'noopener' } } as object;
return <Text {...webProps}>{label}</Text>;
}
return (
<Pressable role="link" onPress={() => Linking.openURL(url)}>
<Text>{label}</Text>
</Pressable>
);
}go deeper
Recall that React Native Web supports an href prop on View and Text that renders a real a element, with hrefAttrs for target, rel and download.
Explain what a real anchor gives that an onPress handler cannot: new-tab gestures, copy link, crawlability and link semantics, plus how hrefAttrs is applied.
Design a cross-platform link component: href on web, onPress on native, typed around web-only props, and no role that replaces the anchor with another element.
Decide link policy for a shared codebase: which navigation must be crawlable anchors on the web, and where routing belongs to the router rather than raw href.
## The problem a link solves on the web On a phone, "tap this row to open a page" is a press handler. In a browser, users expect links: hover to preview the URL, middle-click or Cmd-click to open in a new tab, right-click to copy the address, and search engines expect an `a` element with an `href` to follow. A React Native screen that navigates only through `onPress` renders none of that on the web, because a `div` with a click handler is not a link. ## What href and hrefAttrs do **React Native Web** adds two props to `View` and `Text` that React Native core does not have: - **`href`**: when it is not null, the host element becomes an **`a`** with that `href`, instead of a `div` (or `span`). - **`hrefAttrs`**: an object read **only when `href` is set**, with three keys copied to the anchor: 1. `download` becomes the `download` attribute; 2. `rel` becomes the `rel` attribute (for example `'noopener'` or `'nofollow'`); 3. `target` becomes the `target` attribute, and a value that does not start with `_` gets one prepended, so `'blank'` becomes `_blank`. Keys set to `null` are omitted, and `hrefAttrs` without `href` changes nothing: the element stays a `div`. ```tsx <Text href="https://example.com/terms" hrefAttrs={{ target: 'blank', rel: 'noopener' }}> Terms of service </Text> // => <a href="https://example.com/terms" target="_blank" rel="noopener" dir="auto">Terms of service</a> ``` The anchor keeps React Native Web's reset styles, so it looks like any other `Text` or `View` (no underline, no link color) unless you style it. ## Why not onPress with Linking.openURL | Capability | `href` anchor | `onPress` + `Linking.openURL` | |---|---|---| | Middle-click or Cmd-click to a new tab | yes, native browser behaviour | no, the handler decides | | Context menu "copy link address" | yes | no, there is no address on the element | | Status-bar URL preview on hover | yes | no | | Crawlers can follow it | yes | no | | Screen reader announces a link | yes, an `a` with `href` | only if you add `role="link"` yourself | React Native Web's `Linking.openURL(url)` resolves the URL and calls `window.open(url, '_blank', 'noopener')` when no target is passed (a `tel:` URL assigns `window.location` instead). It is fine for programmatic navigation, but it cannot give the element link behaviour after the fact. ## Interaction with role The anchor is chosen before the role-to-tag mapping is applied, and some roles pick their own tag. A `role` whose element is in React Native Web's map (for example `role="button"`) replaces the `a` with that element, which drops the link semantics you wanted. Leave `role` off, or use `role="link"`, on an element that has an `href`. ## Keeping native builds working - `href` and `hrefAttrs` are **web-only**: the React Native TypeScript types for `View` and `Text` do not declare them, and iOS and Android do nothing with them. - A cross-platform link component therefore usually does both: pass `href` for the web and an `onPress` that navigates on native, chosen with `Platform.OS` or a `.web.tsx` file. - In an app that uses a router with a web target, prefer its link component, which renders an anchor on the web for in-app routes and handles client-side navigation; raw `href` is for external URLs and simple sites. ## Testing and debugging the result - In the browser's element inspector, a linked row shows up as an `a` carrying React Native Web's generated classes, not as a `div` with an event listener. If you see a `div`, the `href` never arrived (often because a wrapper component did not forward it). - A web end-to-end test can assert the destination directly by reading the anchor's `href` attribute instead of clicking and waiting for navigation. - `testID` still becomes `data-testid` on the anchor, so the same test selector works whether the element is a link or not. - Because the anchor keeps the reset styles, a visual review will not reveal the difference; checking keyboard focus (links are tab stops by default) and the hover URL preview does. ## The interview answer in one line Use `href` when the thing is a link, because only an anchor gives the browser, the user and the crawler link behaviour; use `onPress` for actions.
- In React Native Web, what happens to hrefAttrs={{ target: 'blank' }} when href is not set?Nothing: the element stays a `div` (or `span`) and no `target` attribute is written. React Native Web reads `hrefAttrs` only inside the branch that turns the element into an anchor, so the two props must be passed together.
- In React Native Web, what does Linking.openURL do in the browser when called with only a URL?It resolves the URL against the current location and calls `window.open` with a `_blank` target and `noopener`, opening a new tab; a `tel:` URL is assigned to `window.location` instead. Passing a second `target` argument changes where it opens. It does not make the pressed element a link.
saying these in an interview costs you the question
- href is a React Native core prop that also opens URLs on iOS and Android.
- hrefAttrs on its own turns a View into an anchor.
- An onPress calling Linking.openURL is equivalent to a link for users and crawlers.
- target: 'blank' is written verbatim and opens a tab named blank.
- Adding role="button" to a View with href keeps it an anchor.