React Native Basics: Build Your First Mobile App
Styling and Flexbox
In this lesson you will
- Write styles with StyleSheet.create and know how it differs from CSS
- Lay out a screen with flex, flexDirection, alignItems and justifyContent
- Handle screen size and platform differences with useWindowDimensions and Platform
Introduction
React Native styling looks like CSS but is not CSS. There is no stylesheet file and no cascade. You write styles as JavaScript objects, and the layout system is flexbox, with some defaults that differ from the web. This lesson covers both.
StyleSheet
You attach styles to a component with the style prop. The usual way is to collect them with StyleSheet.create:
React (TSX)
import { StyleSheet, Text, View } from "react-native";
export default function Badge() {
return (
<View style={styles.badge}>
<Text style={styles.label}>New</Text>
</View>
);
}
const styles = StyleSheet.create({
badge: { backgroundColor: "#16a34a", paddingHorizontal: 10, paddingVertical: 4, borderRadius: 999 },
label: { color: "white", fontSize: 12, fontWeight: "bold" },
});The differences from CSS, all of which catch beginners:
- Property names are camelCase:
backgroundColor, notbackground-color. - Numbers are plain numbers with no units. They are in density-independent pixels, so
16looks about the same size on every phone. - Values that are words are strings:
"bold","center","#16a34a". - There is no inheritance from a
Viewto its children. Style eachTextyourself (the exception isTextnested insideText). - You can pass an array to combine styles:
style={[styles.a, styles.b]}. Later items win.
Quick quiz
How do you write the CSS value font-size: 16px in React Native?
Flexbox: the whole layout system
Every View lays out its children with flexbox. If you know web flexbox, you only need to learn the differences. The official docs state them: flexDirection defaults to column (the web default is row), flexShrink defaults to 0 (the web is 1), and alignContent defaults to flex-start.
In practice this means children stack top to bottom by default. The properties you use most:
flexDirection:"column"(default) or"row".justifyContent: how to spread children along the main axis (the direction of the stack):"flex-start","center","space-between"and so on.alignItems: how to place children on the cross axis (the other direction):"stretch"(default),"center","flex-start".flex: a single number that says how much of the free space a child takes.flex: 1means "fill all the space you can".gap: space between children.
React (TSX)
import { StyleSheet, Text, View } from "react-native";
export default function Toolbar() {
return (
<View style={styles.screen}>
<View style={styles.row}>
<Text>Left</Text>
<Text>Middle</Text>
<Text>Right</Text>
</View>
<View style={styles.content}>
<Text>This area fills the rest of the screen</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
screen: { flex: 1 },
row: { flexDirection: "row", justifyContent: "space-between", padding: 16, gap: 8 },
content: { flex: 1, alignItems: "center", justifyContent: "center" },
});The outer View has flex: 1, so it fills the whole screen. The row places its three children side by side and pushes them apart. The content view has flex: 1 too, so it takes the space left under the row, and it centres its text on both axes.
Quick quiz
A View contains three Text items and has no flexDirection set. How are they arranged?
Sizes
- A fixed size is a number:
width: 100. - A percentage is a string:
width: "50%". flex: 1shares out leftover space.aspectRatio: 1makes a square from one known side.
React (TSX)
import { StyleSheet, View } from "react-native";
export default function Tiles() {
return (
<View style={styles.row}>
<View style={styles.tile} />
<View style={styles.tile} />
</View>
);
}
const styles = StyleSheet.create({
row: { flexDirection: "row", gap: 12, padding: 16 },
tile: { flex: 1, aspectRatio: 1, backgroundColor: "#5b4bf5", borderRadius: 12 },
});Two tiles share the row equally and each stays square, whatever the phone's width.
Reacting to the screen
Phones come in many sizes and can rotate. The useWindowDimensions hook gives the current width and height and updates when they change:
React (TSX)
import { Text, useWindowDimensions, View } from "react-native";
export default function Responsive() {
const { width } = useWindowDimensions();
const wide = width >= 600;
return (
<View style={{ flexDirection: wide ? "row" : "column", padding: 16 }}>
<Text>{wide ? "Wide layout" : "Narrow layout"}</Text>
</View>
);
}Differences between iPhone and Android
Sometimes you want something different per platform. Platform.OS is "ios" or "android", and Platform.select picks a value:
React (TSX)
import { Platform, StyleSheet, Text, View } from "react-native";
export default function Header() {
return (
<View style={styles.header}>
<Text style={styles.title}>Inbox</Text>
</View>
);
}
const styles = StyleSheet.create({
header: { paddingTop: Platform.select({ ios: 56, android: 32, default: 24 }), paddingHorizontal: 16 },
title: { fontSize: 28, fontWeight: "bold" },
});Use it sparingly. Most of your layout should be identical on both phones.
Try it yourself
Build a card: a View with a background colour, rounded corners and padding, containing a Text heading and a row of two Pressable buttons spaced with justifyContent. Then change flexDirection and alignItems one at a time and watch how the layout moves.
Summary
- Styles are JavaScript objects made with
StyleSheet.create, with camelCase names, unitless numbers and no inheritance. - Flexbox lays everything out, and its default direction is column, not row.
- Use
flex: 1to fill space,useWindowDimensionsfor screen size, andPlatformonly where the phones truly differ.
Lesson complete
+20 XP
Nice work. Keep going while it is fresh.
Sources and further reading