Skip to content

1.2 Core Components

Learning Objectives

  • Understand what React components are and how JSX works in React Native
  • Build layouts using View containers with flexbox properties
  • Render text content with the Text component and inline styles
  • Apply SafeAreaView to handle notches and status bars on mobile devices

In React, a component is a JavaScript function that returns UI. This is the core idea behind React. Instead of manually manipulating the DOM or native views, you write functions that describe what the UI should look like.

In React Native, you write UI using JSX, which looks like HTML but is actually JavaScript:

// This is a React component
export default function App() {
return (
<View>
<Text>Hello, React Native!</Text>
</View>
);
}

When this code runs, React converts it into actual mobile UI elements. On iOS, <View> becomes a native UIView. On Android, it becomes a native android.view.ViewGroup. The JavaScript stays JavaScript, but the UI is 100% native.

Every component is simply a function. React calls your function and uses the returned JSX to build the user interface:

// Step 1: Define a component function
function MyComponent() {
return <Text>I'm a component!</Text>;
}
// Step 2: Use it in JSX
export default function App() {
return (
<View>
<MyComponent /> {/* React calls MyComponent() here */}
</View>
);
}

React re-runs your component function whenever data changes, updating the UI automatically. This is the magic of React.

Diagram

<View> 1 is the most fundamental container in React Native. It’s equivalent to <div> on the web, a box that holds other components and controls their layout using flexbox.

In React Native, styles are JavaScript objects passed to the style prop. Unlike CSS files, you write styles inline using camelCase property names and numeric values (no units needed, all dimensions are in density-independent pixels):

<View
style={{
flex: 1,
backgroundColor: 'lightblue',
padding: 20,
borderRadius: 10,
}}
/>

Key differences from web CSS:

Web CSSReact NativeNotes
background-colorbackgroundColorcamelCase property names
margin: 20pxmargin: 20No units (all values in dp/pt)
border-radiusborderRadiusNumbers automatically in points
flex-directionflexDirectionSame flexbox, but camelCase

React Native uses the same flexbox layout model as CSS web, but with a key difference: the default flexDirection is column (vertical stacking) instead of row (horizontal). Here are the most common properties:

PropertyPurposeExample Values
flexGrows to fill available spaceflex: 1 (fills all space)
flexDirectionArranges children vertically or horizontally'column' (default), 'row'
justifyContentAligns children along main axis'center', 'space-between'
alignItemsAligns children perpendicular to main'center', 'flex-start'
gapSpacing between children10, 20 (in points)

A critical pattern in React Native is flex: 1 on a View. Without it, containers have zero height and collapse:

// ❌ This View has no height! Content is invisible.
<View style={{ backgroundColor: 'blue' }}>
<Text>I'm invisible!</Text>
</View>
// ✅ This View fills available space
<View style={{ flex: 1, backgroundColor: 'blue' }}>
<Text>Now I'm visible!</Text>
</View>
Deeper Dive: Flexbox in React Native vs Web

React Native uses the same flexbox 2 layout model as CSS, but with a few key differences:

  • Default direction: flexDirection: 'column' (not row like web) so children stack vertically by default.
  • Size requirements: Must use flex: 1 on root View to fill the screen. Without it, the container has no height.
  • No wrapping: No automatic wrapping, so you must explicitly set flexWrap: 'wrap'.
  • Everything else: justifyContent, alignItems, gap, marginBottom, etc. work exactly like CSS flexbox.
<View style={{ flex: 1 }}>{/* Content fills available space */}</View>

<Text> 3 is the only component in React Native for displaying text. Unlike web where you can put text directly in a <div>, mobile apps require explicit <Text> elements. This is because text needs special rendering optimization on mobile platforms.

Text supports the same inline styling as View, plus text-specific properties:

<Text
style={{
fontSize: 16,
fontWeight: 'bold',
color: '#333',
marginBottom: 10,
}}
>
Styled text
</Text>

Common text properties:

PropertyPurposeExample Values
fontSizeText size in points12, 16, 20
fontWeightText boldness'normal', 'bold', '600'
colorText color'#333', 'white', 'red'
lineHeightSpace between lines20, 24 (in points)
textAlignHorizontal alignment'left', 'center', 'right'

You can nest <Text> components to create formatted text, similar to <span> tags on the web. Each nested <Text> can have its own styles:

<Text>
I am normal <Text style={{ fontWeight: 'bold' }}>and I am bold</Text>
<Text style={{ color: 'red', fontWeight: 'bold' }}>
{' '}
and I am bold and red
</Text>
</Text>

Behind the scenes, React Native converts nested text into native attributed strings (NSAttributedString on iOS, SpannableString on Android), so you get platform-native text rendering with inline formatting.

Deeper Dive: Text Inheritance and Custom Text Components

Style Inheritance (Limited to Text Subtrees)

Section titled “Style Inheritance (Limited to Text Subtrees)”

Unlike the web where CSS properties cascade through the entire DOM, React Native only allows style inheritance within <Text> component subtrees:

// Parent styles are inherited by nested Text
<Text style={{ fontWeight: 'bold', fontSize: 16 }}>
I am bold and 16pt
<Text style={{ color: 'red' }}>
{' '}
and I inherit bold and fontSize, plus I'm red
</Text>
</Text>

This inheritance only works for <Text> components. You cannot set a font on a <View> and expect child <Text> components to inherit it:

// ❌ This does NOT work - fontFamily on View is ignored
<View style={{ fontFamily: 'Helvetica' }}>
<Text>This won't be Helvetica</Text>
</View>
// ✅ Instead, set styles directly on Text or create a wrapper component
<MyAppText>This will have consistent styling</MyAppText>

Since there’s no global font inheritance, create wrapper components for consistent typography:

MyAppText.tsx
import { Text } from 'react-native';
export function MyAppText({ children, style }: any) {
return (
<Text style={[{ fontFamily: 'Roboto', fontSize: 14 }, style]}>
{children}
</Text>
);
}
// MyAppHeaderText.tsx - Reuse for specific purposes
export function MyAppHeaderText({ children }: any) {
return (
<MyAppText style={{ fontSize: 20, fontWeight: 'bold' }}>
{children}
</MyAppText>
);
}

This gives you consistent typography while still allowing style overrides at the component level.

Modern mobile devices have hardware elements (notches, rounded corners, status bars, clocks) that can obscure your content if you’re not careful. Safe areas define the portions of the screen where your content is guaranteed to be visible and not covered by these interface elements.

<SafeAreaView> from the react-native-safe-area-context library is a <View> component that automatically applies padding to keep your content within safe boundaries. Instead of manually calculating insets for each device, you simply wrap your screen content in SafeAreaView.

import { SafeAreaView } from 'react-native-safe-area-context';
export default function HomeScreen() {
return (
<SafeAreaView style={{ flex: 1 }}>
<Text>Content is in safe area.</Text>
</SafeAreaView>
);
}

In Expo, react-native-safe-area-context comes pre-installed. If needed, install it with:

Terminal window
bunx expo install react-native-safe-area-context
Deeper Dive: How SafeAreaProvider Works

The react-native-safe-area-context library has two parts:

Wraps your entire app at the root level (usually in App.tsx or app/_layout.tsx). It measures the device’s safe area insets once and provides them to all child components:

// App.tsx or app/_layout.tsx
import { SafeAreaProvider } from 'react-native-safe-area-context';
export default function App() {
return <SafeAreaProvider>{/* Your app content */}</SafeAreaProvider>;
}

Used in individual screens to apply the safe area padding. It’s a regular <View> that automatically adds padding based on the insets provided by SafeAreaProvider.

// A screen component
import { SafeAreaView } from 'react-native-safe-area-context';
export default function HomeScreen() {
return (
<SafeAreaView style={{ flex: 1 }}>
<Text>Content is safe.</Text>
</SafeAreaView>
);
}

SafeAreaProvider uses React Context to share safe area measurements with all child components. You’ll learn Context in detail later in the course. For now, just know that it allows data to be “teleported” from a parent provider to any descendant component without passing props through every layer.

This is why we need SafeAreaProvider at the app root and can use SafeAreaView anywhere below it!

To complete these exercises, follow these steps:

  1. Open the Snack by clicking the icon in the toolbar.
  2. If not already logged in, create a free Expo account and sign in.
  3. Click the blue Save button to fork the Snack to your account.
  4. Make changes to the code and save your work.
  5. Submit on Moodle by copy-pasting the Snack URL into the submission box.

Build a 3×3 grid of colored boxes using View and flexbox.

  1. Use flex: 1 on each box to make them fill their container equally
  2. Use flexDirection: 'row' to arrange boxes horizontally in each row
  3. Use gap: 10 to add spacing between boxes
  4. Choose your own colors using hex codes like #FF6B6B
  5. Optional: Add borderRadius to round the corners
Hint

For the grid layout, think about how to organize the rows. Each row should be a View with flex: 1 and flexDirection: 'row'. Inside each row, place three boxes, each with flex: 1 and a different color.

Key pattern:

<View style={{ flex: 1, flexDirection: 'row', gap: 10 }}>
<View style={{ flex: 1, backgroundColor: '#FF6B6B' }} />
<View style={{ flex: 1, backgroundColor: '#4ECDC4' }} />
<View style={{ flex: 1, backgroundColor: '#FFD93D' }} />
</View>
  • Components are functions that return JSX describing the UI.
  • View is the container; use flex: 1 to fill space and flexbox for layout.
  • Text is the only way to display text; wrap all text in <Text> components.
  • SafeAreaView automatically handles notches and status bars on mobile devices.
  • Inline styles are JavaScript objects with camelCase properties.
  • Flexbox in React Native works like web flexbox, but defaults to vertical (column) layout.
  1. https://reactnative.dev/docs/view

  2. https://reactnative.dev/docs/flexbox

  3. https://reactnative.dev/docs/text