A View is the fundamental container, with layout, style, touch handling and accessibility. It maps to an android.view.ViewGroup subclass on Android and a UIView on iOS, draws only its background, border and shadow, and cannot hold bare text.
Layout is flexbox, computed by Meta's C++ Yoga engine with the rules you know from CSS (Front-End Web Development). Only the defaults differ, which is why a first screen stacks vertically:
| Property | React Native 36,878 default | CSS default |
|---|---|---|
| flexDirection | column | row |
| alignContent | flex-start | stretch |
| flexShrink | 0 | 1 |
| flex | one number only | shorthand, up to three values |
Every element is a flex container, lengths are unitless density-independent pixels (or percentage strings), styles never cascade from a parent View, and gap works as on the web. Each screen in this section is a component in src/demos/ that App.tsx renders inside the SafeAreaProvider of react-native-safe-area-context 2,760 (core SafeAreaView was deprecated in React Native 0.81). They share one wrapper and style sheet:
import { ReactNode } from 'react';
import { StyleSheet } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
export const Screen = ({ children }: { children: ReactNode }) => (
<SafeAreaView style={ui.screen}>{children}</SafeAreaView>
);
export const ui = StyleSheet.create({
screen: { flex: 1, padding: 16, gap: 12, backgroundColor: '#eceff1' },
card: { padding: 12, borderRadius: 8, backgroundColor: '#fff' },
h1: { fontSize: 24, fontWeight: '700', color: '#212121' },
label: { fontWeight: '600', color: '#37474f' },
input: { borderWidth: 1, borderColor: '#90a4ae', borderRadius: 6, padding: 10, fontSize: 16 },
error: { color: '#c62828' },
button: { padding: 12, borderRadius: 6, alignItems: 'center', backgroundColor: '#1565c0' },
buttonText: { color: '#fff', fontWeight: '700' },
});The first screen lays out the six BookNest books as cards. Each card is a row; the text column takes the remaining width with flex: 1, and marginTop: 'auto' pushes the price to the bottom of the card, whose height comes from the cover's aspectRatio:
{books.map((book) => (
<View key={book.id} style={[ui.card, { flexDirection: 'row', gap: 12 }]}>
<View style={{ width: 56, aspectRatio: 2 / 3, backgroundColor: '#1565c0' }} />
<View style={{ flex: 1 }}>
<Text style={{ fontSize: 17, fontWeight: '600' }}>{book.title}</Text>
<Text style={ui.label}>{book.author}</Text>
<View style={{ flexDirection: 'row', justifyContent: 'space-between',
marginTop: 'auto' }}>
<Text style={{ fontWeight: '700' }}>${book.price.toFixed(2)}</Text>
<Text>{book.rating} ★</Text>
</View>
</View>
</View>
))}Like most listings here, it shows only what sits inside <Screen>; the result is the left screen of the figure in Long Text. Two pitfalls catch web developers: with flexShrink at 0, a long title can push its siblings off screen (flex: 1 on the column fixes it), and flex: 1 only fills space its parent has, so a blank screen usually has a parent without a height.