React is the library; React Native uses it to build iOS and Android apps. With React on the web you render HTML elements such as div and button into a browser page. React Native renders its own components, such as View and Text, which become real platform views. Components, props, state and hooks work the same way in both.
| Question | React (web, react-dom) | React Native |
|---|---|---|
| Runs where? | Web browsers | iOS and Android apps |
| Building blocks | HTML elements: div, p, img, input | Core components: View, Text, Image, TextInput |
| Styling | CSS files, className, or a style object | style prop with JavaScript objects, often from StyleSheet.create |
| Default flex direction | row (when display: flex) | column |
| Tap or click handler | onClick | onPress |
| Shared | Components, JSX, props, state, hooks | Components, JSX, props, state, hooks |
Updated
The quickest way to see the difference is to translate a web element into its native counterpart. Search the map below for an HTML tag, a prop or a CSS habit, and each row gives the React Native replacement with a short note on what behaves differently.
Showing 15 of 15 rows
| React on the web | React Native | What changes |
|---|---|---|
<div> | <View> | A container with flexbox layout, style and touch handling. It does not scroll. |
<p>, <span>, <h1> | <Text> | All text must be inside Text. Nested Text inherits styles; there are no heading tags. |
<img src> | <Image source={{ uri }}> | Network images need an explicit width and height. Local files use require(). |
<input type="text"> | <TextInput> | onChangeText passes the new string directly instead of an event. |
<textarea> | <TextInput multiline> | The multiline prop allows several lines of text. |
<input type="password"> | <TextInput secureTextEntry> | Hides the typed text. It does not work together with multiline. |
<input type="checkbox"> | <Switch> | A controlled boolean input: update value from onValueChange. |
<button> | <Button> or <Pressable> | Button takes a title prop; Pressable wraps any children you want to make tappable. |
onClick | onPress | Pressable also offers onPressIn, onPressOut and onLongPress. |
<div> with overflow: auto | <ScrollView> | Renders all of its children at once, so keep it for short content. |
<ul> with items.map() | <FlatList> | Renders long lists efficiently. Needs data and renderItem; keyExtractor sets each key. |
<a href="https://..."> | Linking.openURL(url) | Opens the URL with an installed app such as the browser. Wrap it in a Pressable for a tappable link. |
className + CSS file | style={styles.card} | Styles are objects, usually defined with StyleSheet.create. Pass an array to combine them; the last wins. |
background-color | backgroundColor | Style names are camelCase, as in React's own style prop on the web. |
display: flex (row) | flexDirection: "column" (default) | Every View is a flex container and stacks children vertically unless told otherwise. |
The component logic is identical: the same props, the same useState call, the same handler. Only the elements and the styling change.
HTML elements, a CSS class and onClick. The browser lays out the button after the text.
import { useState } from "react";
export function LikeCard({ title }) {
const [likes, setLikes] = useState(0);
return (
<div className="card">
<p className="card-title">{title}</p>
<button onClick={() => setLikes(likes + 1)}>Like ({likes})</button>
</div>
);
}View, Text and Pressable from react-native, styles from StyleSheet.create, and onPress in place of onClick.
import { useState } from "react";
import { Pressable, StyleSheet, Text, View } from "react-native";
export function LikeCard({ title }) {
const [likes, setLikes] = useState(0);
return (
<View style={styles.card}>
<Text style={styles.title}>{title}</Text>
<Pressable onPress={() => setLikes(likes + 1)} style={styles.button}>
<Text>Like ({likes})</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
card: { padding: 16, borderRadius: 12, backgroundColor: "#fff" },
title: { fontSize: 18, fontWeight: "600", marginBottom: 8 },
button: { alignSelf: "flex-start", paddingVertical: 8, paddingHorizontal: 12 },
});FlatList only renders what is near the screen, which keeps long lists smooth. keyExtractor plays the role of the key prop.
import { FlatList, Text } from "react-native";
const products = [
{ id: "p1", name: "Desk lamp" },
{ id: "p2", name: "Notebook" },
];
export function ProductList() {
return (
<FlatList
data={products}
keyExtractor={(item) => item.id}
renderItem={({ item }) => <Text>{item.name}</Text>}
/>
);
}
Both use the react package. Function components, JSX, props, state, effects, context and custom hooks are identical, and a hook such as useState behaves the same on a phone as in a browser.
What differs is the renderer. On the web, react-dom turns components into HTML elements. In React Native, components such as View and Text are turned into platform views, so everything that depends on the DOM, from document.querySelector to CSS selectors, is not available.
In React Native every string must sit inside a Text component; a bare string under a View raises an error. Style inheritance is also limited: nested Text inherits from its parent Text, but a View passes nothing down to its children.
Flexbox is the layout system, but flexDirection defaults to column, alignContent to flex-start and flexShrink to 0, and flex accepts a single number only. Layouts copied from web CSS often need flexDirection: "row" added.
Choose React for anything people open in a browser: marketing sites, dashboards, web apps and content that must be found by search engines. Choose React Native when you need an app in the iOS and Android stores, with access to device features and native navigation.
Many teams use both: a React web app plus a React Native app sharing types and API code. If you are also weighing Next.js on the web side, the Next.js vs React guide on this site covers that choice.
No. React is the component library; React Native is a framework that uses React to drive native mobile views. You write components the same way, but you render View, Text and other native components instead of HTML, and there is no browser DOM.
Not directly. There are no div or span elements and no CSS files. Styles are JavaScript objects with camelCase names that mostly mirror CSS, and layout uses flexbox with a few different defaults.
React first, in most cases. React Native's own documentation teaches React's components, JSX, props and state as the foundation, and practising them on the web gives you faster feedback.
The logic can be shared: types, API clients, validation and hooks that do not touch the DOM. Screens and components usually are not, because they render different primitives.
Yes. React Native's documentation explains that at runtime it creates the matching Android and iOS views for its components, so a View becomes a native view rather than a web page in a wrapper.
Related: Next.js vs React, React with TypeScript, React Native text input, Forms in React Native, TypeScript data types.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.