✍️ Text: Typography in Native
Displaying and styling text the React Native way
🎯 Learning Objectives
By the end of this lesson, you will be able to:
- Understand why Text is required and how it differs from web text
- Apply typography styles like fontSize, fontWeight, and lineHeight
- Use system fonts and load custom fonts with Expo
- Control text overflow with numberOfLines and ellipsizeMode
- Create inline styled text using nested Text components
- Implement accessible text for screen readers
⏱️ Estimated Time: 25-35 minutes
📑 In This Lesson
Why Text is Required
In React Native, you cannot place raw text directly inside a View. Every piece of text must be wrapped in a Text component. This is one of the first "gotchas" web developers encounter.
⚠️ This Will Crash Your App
// ❌ WRONG - Raw text in View causes a crash
<View>
Hello World
</View>
// Error: Text strings must be rendered within a <Text> component
The correct approach:
// ✅ CORRECT - Text wrapped in Text component
<View>
<Text>Hello World</Text>
</View>
Why This Requirement Exists
This isn't arbitrary — it reflects how native platforms work:
📱 iOS (UIKit)
UIView cannot display text directly. You need a UILabel or UITextView — specialized views designed for text rendering.
🤖 Android
android.view.View has no text rendering. You need a TextView — a specific component for displaying text.
React Native's Text component maps to these native text views, which is why it's required. The web's ability to put text anywhere is actually the exception, not the rule.
React Native's Text bridges to each platform's native text component
📖 Key Insight
Think of Text as the only way to render text in React Native. Just as you need View for containers, you need Text for any string that appears on screen.
Typography: Web vs Native
If you're used to CSS typography, you'll find some familiar concepts and some surprising differences.
Key Differences
| Aspect | Web CSS | React Native |
|---|---|---|
| Style inheritance | Text styles cascade down the DOM | ❌ No inheritance — each Text needs its own styles |
| Units | px, em, rem, %, vw, vh | Unitless numbers (density-independent pixels) |
| Font loading | @font-face, Google Fonts | expo-font or native linking |
| Default font | Browser default (usually Times) | System font (San Francisco on iOS, Roboto on Android) |
| line-height | Unitless multiplier or length | Absolute number only (like px) |
| letter-spacing | em or px | Absolute number only |
| text-decoration | underline, line-through, etc. | textDecorationLine, textDecorationStyle, textDecorationColor |
The No-Inheritance Surprise
This is probably the biggest mental shift. On the web:
<!-- Web: Styles cascade down -->
<div style="font-family: Arial; color: blue;">
<p>This is blue Arial</p>
<p>So is this!</p>
</div>
In React Native, this does NOT work the same way:
// ❌ WRONG EXPECTATION - Styles don't cascade
<View style={{ fontFamily: 'Arial' }}> {/* View can't even have fontFamily! */}
<Text>This won't inherit anything</Text>
</View>
// ✅ CORRECT - Apply styles to each Text
<View>
<Text style={styles.bodyText}>Styled text</Text>
<Text style={styles.bodyText}>Also styled</Text>
</View>
✅ Exception: Nested Text
The ONE place styles do inherit is within nested Text components. A child Text will inherit styles from its parent Text:
<Text style={{ fontSize: 16, color: 'blue' }}>
This is blue.
<Text style={{ fontWeight: 'bold' }}>This is blue AND bold.</Text>
</Text>
We'll explore this powerful pattern in the Nested Text section.
Density-Independent Pixels
React Native uses unitless numbers that represent density-independent pixels (dp). The framework automatically scales these based on screen density:
// This is NOT 16 physical pixels
// It's 16 density-independent pixels
<Text style={{ fontSize: 16 }}>Hello</Text>
On a high-density screen (like iPhone 14 Pro), 16dp might render as 48 physical pixels. On a lower-density screen, it might be 32 physical pixels. The text appears the same physical size on both devices.
Density-independent pixels ensure consistent text size across devices
Styling Text
Text accepts a rich set of style properties. Let's explore the most important ones.
Core Typography Styles
import { Text, StyleSheet } from 'react-native';
function TypographyDemo() {
return (
<>
<Text style={styles.heading}>Main Heading</Text>
<Text style={styles.subheading}>Subheading Text</Text>
<Text style={styles.body}>Body text with normal weight and size.</Text>
<Text style={styles.caption}>Small caption text</Text>
</>
);
}
const styles = StyleSheet.create({
heading: {
fontSize: 28,
fontWeight: 'bold', // 'normal', 'bold', '100'-'900'
color: '#1a1a2e',
letterSpacing: 0.5, // Space between characters
marginBottom: 8,
},
subheading: {
fontSize: 20,
fontWeight: '600', // Semi-bold
color: '#444',
marginBottom: 12,
},
body: {
fontSize: 16,
fontWeight: 'normal',
color: '#333',
lineHeight: 24, // Absolute value, not multiplier
marginBottom: 8,
},
caption: {
fontSize: 12,
fontWeight: '300', // Light
color: '#888',
fontStyle: 'italic',
},
});
Complete Style Reference
| Property | Values | Notes |
|---|---|---|
fontSize |
number | Size in density-independent pixels |
fontWeight |
'normal', 'bold', '100'-'900' |
String values only (not numbers) |
fontStyle |
'normal', 'italic' |
No 'oblique' like CSS |
fontFamily |
string | Font name (must be loaded) |
color |
string | Any valid color format |
lineHeight |
number | Absolute value (not multiplier) |
letterSpacing |
number | Space between characters |
textAlign |
'auto', 'left', 'right', 'center', 'justify' |
Horizontal alignment |
textTransform |
'none', 'uppercase', 'lowercase', 'capitalize' |
Case transformation |
textDecorationLine |
'none', 'underline', 'line-through', 'underline line-through' |
Text decoration |
textDecorationStyle |
'solid', 'double', 'dotted', 'dashed' |
iOS only |
textDecorationColor |
string | iOS only |
textShadowColor |
string | Shadow color |
textShadowOffset |
{ width: number, height: number } |
Shadow offset |
textShadowRadius |
number | Shadow blur radius |
fontWeight Gotcha
⚠️ fontWeight Must Be a String
// ❌ WRONG - Number value
fontWeight: 600
// ✅ CORRECT - String value
fontWeight: '600'
Unlike CSS where both work, React Native requires string values for fontWeight.
lineHeight Behavior
On the web, you might use line-height: 1.5 as a multiplier. In React Native, lineHeight is an absolute value:
// Web CSS
line-height: 1.5; // 1.5x the font size
// React Native - calculate it yourself
fontSize: 16,
lineHeight: 24, // 16 * 1.5 = 24
💡 Pro Tip: Create a Helper
// Create text styles with proportional line height
const createTextStyle = (fontSize: number, lineHeightMultiplier = 1.5) => ({
fontSize,
lineHeight: fontSize * lineHeightMultiplier,
});
// Usage
const styles = StyleSheet.create({
body: {
...createTextStyle(16, 1.5), // fontSize: 16, lineHeight: 24
color: '#333',
},
});
Working with Fonts
React Native uses the system font by default — San Francisco on iOS and Roboto on Android. For custom fonts, you'll need to load them explicitly.
System Fonts
Without specifying a fontFamily, your text uses the platform's default:
// Uses San Francisco on iOS, Roboto on Android
<Text style={{ fontSize: 16 }}>System font text</Text>
You can also explicitly request platform-specific system fonts:
import { Platform } from 'react-native';
const styles = StyleSheet.create({
text: {
fontFamily: Platform.select({
ios: 'Helvetica Neue',
android: 'Roboto',
default: 'System',
}),
},
});
Loading Custom Fonts with Expo
Expo makes loading custom fonts straightforward with the expo-font package and the useFonts hook:
import { Text, View } from 'react-native';
import { useFonts } from 'expo-font';
import * as SplashScreen from 'expo-splash-screen';
import { useEffect } from 'react';
// Prevent splash screen from hiding until fonts load
SplashScreen.preventAutoHideAsync();
export default function App() {
const [fontsLoaded] = useFonts({
'Poppins-Regular': require('./assets/fonts/Poppins-Regular.ttf'),
'Poppins-Bold': require('./assets/fonts/Poppins-Bold.ttf'),
'Poppins-Italic': require('./assets/fonts/Poppins-Italic.ttf'),
});
useEffect(() => {
if (fontsLoaded) {
SplashScreen.hideAsync();
}
}, [fontsLoaded]);
if (!fontsLoaded) {
return null; // Or a loading indicator
}
return (
<View style={{ flex: 1, padding: 20 }}>
<Text style={{ fontFamily: 'Poppins-Bold', fontSize: 24 }}>
Custom Font Heading
</Text>
<Text style={{ fontFamily: 'Poppins-Regular', fontSize: 16 }}>
Body text with Poppins Regular
</Text>
</View>
);
}
✅ Font Loading Best Practices
- Load fonts at app startup, before rendering any text
- Use the splash screen to hide the loading state
- Keep font files in an
assets/fontsfolder - Use descriptive names that include weight/style (e.g., "Poppins-Bold")
Using Google Fonts with Expo
Expo provides pre-packaged Google Fonts that are even easier to use:
# Install a Google Font package
npx expo install @expo-google-fonts/inter expo-font
import { Text, View } from 'react-native';
import { useFonts, Inter_400Regular, Inter_700Bold } from '@expo-google-fonts/inter';
import * as SplashScreen from 'expo-splash-screen';
import { useEffect } from 'react';
SplashScreen.preventAutoHideAsync();
export default function App() {
const [fontsLoaded] = useFonts({
Inter_400Regular,
Inter_700Bold,
});
useEffect(() => {
if (fontsLoaded) {
SplashScreen.hideAsync();
}
}, [fontsLoaded]);
if (!fontsLoaded) return null;
return (
<View style={{ flex: 1, padding: 20 }}>
<Text style={{ fontFamily: 'Inter_700Bold', fontSize: 24 }}>
Inter Bold Heading
</Text>
<Text style={{ fontFamily: 'Inter_400Regular', fontSize: 16 }}>
Inter Regular body text
</Text>
</View>
);
}
Font Weight Variants
Unlike the web where you can use font-weight: 700 with any font, React Native requires separate font files for each weight:
Each font weight needs its own file and fontFamily name
Useful Text Props
Beyond styling, Text has several props that control behavior. These are essential for real-world apps.
numberOfLines and ellipsizeMode
Control how text truncates when it exceeds available space:
// Truncate to single line with ellipsis at end
<Text numberOfLines={1} ellipsizeMode="tail">
This is a very long text that will be truncated...
</Text>
// Show first 3 lines only
<Text numberOfLines={3} ellipsizeMode="tail">
{longArticlePreview}
</Text>
ellipsizeMode Options
| Value | Behavior | Example |
|---|---|---|
'tail' |
Truncate at end (default) | "Hello Wor..." |
'head' |
Truncate at beginning | "...llo World" |
'middle' |
Truncate in middle | "Hel...orld" |
'clip' |
Cut off without ellipsis | "Hello Wor" |
selectable
By default, users cannot select or copy text. Enable selection with:
// Allow user to select and copy this text
<Text selectable={true}>
This text can be selected and copied
</Text>
// Common use case: copyable codes or IDs
<Text selectable style={styles.code}>
Order #ABC-12345-XYZ
</Text>
onPress and onLongPress
Text can respond to touch events directly:
// Text as a link
<Text
style={styles.link}
onPress={() => Linking.openURL('https://example.com')}
>
Visit our website
</Text>
// Text with long press action
<Text
onPress={() => console.log('Tapped')}
onLongPress={() => console.log('Long pressed')}
>
Tap or hold me
</Text>
💡 When to Use Text onPress vs Pressable
- Text onPress: Simple inline links within paragraphs
- Pressable: Buttons, cards, complex interactive elements with visual feedback
Text's onPress doesn't provide visual feedback by default — consider Pressable for better UX on buttons.
adjustsFontSizeToFit (iOS)
Automatically shrink text to fit within its container:
// Text shrinks to fit the container width
<Text
numberOfLines={1}
adjustsFontSizeToFit
minimumFontScale={0.5} // Don't shrink below 50% of original size
style={{ fontSize: 24 }}
>
This heading will shrink if needed
</Text>
⚠️ Platform Note
adjustsFontSizeToFit works reliably on iOS. On Android, behavior can be inconsistent. For cross-platform solutions, consider calculating font size based on container width.
All Text Props Reference
<Text
// Truncation
numberOfLines={2}
ellipsizeMode="tail"
// Selection
selectable={true}
// Touch events
onPress={() => {}}
onLongPress={() => {}}
onPressIn={() => {}}
onPressOut={() => {}}
// iOS specific
adjustsFontSizeToFit={true}
minimumFontScale={0.5}
suppressHighlighting={false} // Disable press highlight
// Android specific
android_hyphenationFrequency="normal" // 'none', 'normal', 'full'
textBreakStrategy="highQuality" // 'simple', 'highQuality', 'balanced'
// Layout
onLayout={(event) => console.log(event.nativeEvent.layout)}
onTextLayout={(event) => console.log(event.nativeEvent.lines)}
// Accessibility (covered in depth later)
accessible={true}
accessibilityRole="text"
accessibilityLabel="Description for screen readers"
// Testing
testID="my-text"
>
Content here
</Text>
Nested Text for Inline Styles
One of Text's most powerful features is the ability to nest Text components. This enables inline styling — applying different styles to parts of the same paragraph.
Basic Inline Styling
// Bold word within a sentence
<Text style={styles.paragraph}>
This is a <Text style={styles.bold}>very important</Text> message.
</Text>
// Multiple inline styles
<Text style={styles.paragraph}>
You can mix <Text style={styles.bold}>bold</Text>,
<Text style={styles.italic}>italic</Text>, and
<Text style={styles.highlight}>highlighted</Text> text.
</Text>
const styles = StyleSheet.create({
paragraph: {
fontSize: 16,
color: '#333',
lineHeight: 24,
},
bold: {
fontWeight: 'bold',
},
italic: {
fontStyle: 'italic',
},
highlight: {
backgroundColor: '#ffeb3b',
color: '#333',
},
});
Style Inheritance in Nested Text
Child Text components inherit styles from their parent Text:
<Text style={{ fontSize: 16, color: 'blue' }}>
This is blue.
<Text style={{ fontWeight: 'bold' }}>
This is blue AND bold.
</Text>
<Text style={{ color: 'red' }}>
This overrides to red, keeps fontSize: 16.
</Text>
</Text>
flowchart TD
A["Parent Text
fontSize: 16, color: blue"] --> B["Child Text 1
fontWeight: bold
Inherits: fontSize: 16, color: blue"]
A --> C["Child Text 2
color: red
Inherits: fontSize: 16
Overrides: color"]
style A fill:#e3f2fd,stroke:#1976d2
style B fill:#e8f5e9,stroke:#4caf50
style C fill:#ffebee,stroke:#f44336
Nested Text inherits parent styles, but can override specific properties
Inline Links
A common pattern is creating tappable links within paragraphs:
import { Text, Linking, StyleSheet } from 'react-native';
function TermsText() {
return (
<Text style={styles.terms}>
By signing up, you agree to our{' '}
<Text
style={styles.link}
onPress={() => Linking.openURL('https://example.com/terms')}
>
Terms of Service
</Text>
{' '}and{' '}
<Text
style={styles.link}
onPress={() => Linking.openURL('https://example.com/privacy')}
>
Privacy Policy
</Text>
.
</Text>
);
}
const styles = StyleSheet.create({
terms: {
fontSize: 14,
color: '#666',
textAlign: 'center',
},
link: {
color: '#2196F3',
textDecorationLine: 'underline',
},
});
✅ Note the {' '} Spacers
When nesting Text components, whitespace handling can be tricky. Use {' '} to explicitly add spaces between inline elements. Otherwise, words might run together.
Rich Text Patterns
// Price with currency styling
function Price({ amount, currency = 'USD' }) {
return (
<Text style={styles.price}>
<Text style={styles.currency}>{currency} </Text>
<Text style={styles.amount}>{amount.toFixed(2)}</Text>
</Text>
);
}
// Username mention
function PostContent({ text, mentions }) {
// Simplified - real implementation would parse text
return (
<Text style={styles.post}>
Great meeting with <Text style={styles.mention}>@johndoe</Text> today!
</Text>
);
}
// Code inline
function DocText() {
return (
<Text style={styles.doc}>
Use the <Text style={styles.code}>useState</Text> hook to manage state.
</Text>
);
}
Text Accessibility
Text is automatically accessible to screen readers, but you can enhance the experience with additional props.
Automatic Accessibility
By default, Text components are read by screen readers. The text content becomes the accessibility label:
// Screen reader announces: "Hello World"
<Text>Hello World</Text>
Custom Accessibility Labels
Sometimes the visible text isn't sufficient for screen reader users:
// Visible: "5 min" — Screen reader: "5 minutes ago"
<Text accessibilityLabel="5 minutes ago">5 min</Text>
// Visible: "$99" — Screen reader: "99 dollars"
<Text accessibilityLabel="99 dollars">$99</Text>
// Icon-only text needs a label
<Text accessibilityLabel="Favorite">❤️</Text>
Accessibility Roles for Text
// Heading for navigation
<Text
accessibilityRole="header"
style={styles.heading}
>
Shopping Cart
</Text>
// Link
<Text
accessibilityRole="link"
accessibilityHint="Opens in browser"
onPress={() => Linking.openURL(url)}
>
Learn more
</Text>
// Alert or important message
<Text accessibilityRole="alert">
Payment failed. Please try again.
</Text>
Accessibility for Nested Text
When Text is nested, screen readers combine them into a single announcement by default:
// Screen reader announces: "Price 99 dollars 99 cents"
<Text>
Price{' '}
<Text style={styles.dollars}>$99</Text>
<Text style={styles.cents}>.99</Text>
</Text>
// To make child text separately accessible:
<Text>
Price{' '}
<Text
accessible={true}
accessibilityLabel="99 dollars and 99 cents"
>
$99.99
</Text>
</Text>
Dynamic Content Announcements
For content that updates (like a counter), use accessibility live regions:
import { AccessibilityInfo } from 'react-native';
function Counter({ count }) {
useEffect(() => {
// Announce count changes to screen readers
AccessibilityInfo.announceForAccessibility(`Count is now ${count}`);
}, [count]);
return (
<Text
accessibilityLiveRegion="polite"
accessibilityLabel={`Count: ${count}`}
>
{count}
</Text>
);
}
💡 Testing Accessibility
- iOS: Enable VoiceOver in Settings → Accessibility → VoiceOver
- Android: Enable TalkBack in Settings → Accessibility → TalkBack
- Expo Go: Works with device accessibility features enabled
Test your app with these screen readers regularly — it's the only way to truly understand the experience.
Hands-On Exercises
Practice makes perfect! These exercises will help you master Text styling and behavior.
Exercise 1: Typography Scale
Goal: Create a typography scale component that demonstrates different text sizes and weights.
Requirements:
- Display 5 text levels: H1 (32px bold), H2 (24px semibold), H3 (20px medium), Body (16px regular), Caption (12px light)
- Each should have appropriate line height (1.3x for headings, 1.5x for body)
- Use a consistent color scheme (dark for headings, gray for body, light gray for caption)
💡 Hint
Create a StyleSheet with separate styles for each level. Remember lineHeight must be an absolute number, not a multiplier.
✅ Solution
import { View, Text, StyleSheet } from 'react-native';
export default function TypographyScale() {
return (
<View style={styles.container}>
<Text style={styles.h1}>Heading 1</Text>
<Text style={styles.h2}>Heading 2</Text>
<Text style={styles.h3}>Heading 3</Text>
<Text style={styles.body}>
Body text for paragraphs and general content.
This should be comfortable to read in longer passages.
</Text>
<Text style={styles.caption}>
Caption text for labels, timestamps, and metadata
</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#fff',
gap: 16,
},
h1: {
fontSize: 32,
fontWeight: 'bold',
color: '#1a1a2e',
lineHeight: 42, // 32 * 1.3
},
h2: {
fontSize: 24,
fontWeight: '600',
color: '#1a1a2e',
lineHeight: 31, // 24 * 1.3
},
h3: {
fontSize: 20,
fontWeight: '500',
color: '#333',
lineHeight: 26, // 20 * 1.3
},
body: {
fontSize: 16,
fontWeight: 'normal',
color: '#555',
lineHeight: 24, // 16 * 1.5
},
caption: {
fontSize: 12,
fontWeight: '300',
color: '#888',
lineHeight: 18, // 12 * 1.5
},
});
Exercise 2: Truncated Card Preview
Goal: Create an article preview card with truncated text.
Requirements:
- Title: max 2 lines, truncate with ellipsis at end
- Preview text: max 3 lines, truncate with ellipsis
- Author and date on a single line (use "•" as separator)
- Card should have padding, rounded corners, and subtle shadow
💡 Hint
Use numberOfLines and ellipsizeMode="tail". The author/date line can be a View with flexDirection: 'row'.
✅ Solution
import { View, Text, StyleSheet } from 'react-native';
const article = {
title: 'Understanding React Native Performance: A Deep Dive into Optimization Techniques',
preview: 'Learn how to build blazing fast mobile apps with React Native. We cover memoization, list optimization, image caching, and more advanced techniques that will make your app feel native.',
author: 'Jane Developer',
date: 'Dec 27, 2024',
};
export default function ArticleCard() {
return (
<View style={styles.card}>
<Text
style={styles.title}
numberOfLines={2}
ellipsizeMode="tail"
>
{article.title}
</Text>
<Text
style={styles.preview}
numberOfLines={3}
ellipsizeMode="tail"
>
{article.preview}
</Text>
<View style={styles.meta}>
<Text style={styles.author}>{article.author}</Text>
<Text style={styles.separator}> • </Text>
<Text style={styles.date}>{article.date}</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
card: {
backgroundColor: 'white',
borderRadius: 12,
padding: 16,
margin: 16,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 3,
},
title: {
fontSize: 18,
fontWeight: 'bold',
color: '#1a1a2e',
marginBottom: 8,
lineHeight: 24,
},
preview: {
fontSize: 14,
color: '#666',
lineHeight: 21,
marginBottom: 12,
},
meta: {
flexDirection: 'row',
alignItems: 'center',
},
author: {
fontSize: 12,
color: '#2196F3',
fontWeight: '500',
},
separator: {
fontSize: 12,
color: '#ccc',
},
date: {
fontSize: 12,
color: '#999',
},
});
Exercise 3: Inline Rich Text
Goal: Create a paragraph with mixed inline styles, including a tappable link.
Requirements:
- Normal paragraph text in dark gray
- One word in bold
- One phrase in italic
- An inline
codesnippet with background color - A tappable link (underlined, blue) that logs to console when pressed
💡 Hint
Use nested Text components. For the code style, use backgroundColor and fontFamily: 'monospace' (or platform-specific monospace font).
✅ Solution
import { Text, StyleSheet, Platform } from 'react-native';
export default function RichParagraph() {
return (
<Text style={styles.paragraph}>
React Native is a <Text style={styles.bold}>powerful</Text> framework
for building mobile apps. It uses{' '}
<Text style={styles.italic}>native components</Text> under the hood,
which means your app feels truly native. To get started, run{' '}
<Text style={styles.code}>npx create-expo-app</Text>{' '}
in your terminal. For more info, check out the{' '}
<Text
style={styles.link}
onPress={() => console.log('Link pressed!')}
>
official documentation
</Text>.
</Text>
);
}
const styles = StyleSheet.create({
paragraph: {
fontSize: 16,
color: '#444',
lineHeight: 26,
padding: 20,
},
bold: {
fontWeight: 'bold',
},
italic: {
fontStyle: 'italic',
},
code: {
fontFamily: Platform.select({
ios: 'Menlo',
android: 'monospace',
}),
backgroundColor: '#f0f0f0',
paddingHorizontal: 4,
fontSize: 14,
color: '#d63384',
},
link: {
color: '#2196F3',
textDecorationLine: 'underline',
},
});
Challenge: Selectable Quote Block
🏆 Bonus Challenge
Goal: Create a styled quote block with attribution that users can select and copy.
Features:
- Large opening quotation mark (decorative)
- Quote text in italic, slightly larger font
- Attribution line with author name (bold) and source (regular)
- Left border accent (like blockquote)
- Selectable text for the quote and attribution
✅ Solution
import { View, Text, StyleSheet } from 'react-native';
export default function QuoteBlock() {
return (
<View style={styles.container}>
<View style={styles.quoteBox}>
<Text style={styles.quoteMark}>"</Text>
<Text style={styles.quoteText} selectable>
The only way to do great work is to love what you do.
If you haven't found it yet, keep looking. Don't settle.
</Text>
<Text style={styles.attribution} selectable>
— <Text style={styles.author}>Steve Jobs</Text>,
Stanford Commencement Speech 2005
</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 20,
},
quoteBox: {
backgroundColor: '#f8f9fa',
borderLeftWidth: 4,
borderLeftColor: '#667eea',
paddingVertical: 20,
paddingHorizontal: 24,
borderRadius: 8,
},
quoteMark: {
fontSize: 60,
color: '#667eea',
lineHeight: 60,
marginBottom: -20,
marginLeft: -8,
opacity: 0.5,
},
quoteText: {
fontSize: 18,
fontStyle: 'italic',
color: '#333',
lineHeight: 28,
marginBottom: 16,
},
attribution: {
fontSize: 14,
color: '#666',
},
author: {
fontWeight: 'bold',
color: '#444',
},
});
Summary
🎉 Key Takeaways
- Text is required for all text — you cannot put raw strings inside View
- No style inheritance — except within nested Text components
- Units are density-independent — just use numbers, no "px" suffix
- lineHeight is absolute — calculate it from fontSize (e.g., 16 * 1.5 = 24)
- fontWeight must be a string — use '600' not 600
- Load custom fonts with expo-font — each weight needs a separate file
- Use numberOfLines for truncation — combine with ellipsizeMode
- Nest Text for inline styles — child Text inherits from parent Text
- Add accessibility labels — especially for abbreviations and icons
Quick Reference
import { Text, StyleSheet, Platform } from 'react-native';
// Basic styled text
<Text style={styles.body}>Hello World</Text>
// Truncated text
<Text numberOfLines={2} ellipsizeMode="tail">Long text...</Text>
// Selectable text
<Text selectable>Copy me!</Text>
// Nested/inline styling
<Text style={styles.paragraph}>
Normal text with <Text style={styles.bold}>bold</Text> word.
</Text>
// Tappable text
<Text onPress={() => handlePress()}>Tap me</Text>
const styles = StyleSheet.create({
body: {
fontSize: 16,
fontWeight: 'normal', // String, not number
color: '#333',
lineHeight: 24, // Absolute, not multiplier
letterSpacing: 0.5,
textAlign: 'left',
},
bold: { fontWeight: 'bold' },
paragraph: { fontSize: 16 },
});
🚀 What's Next?
Now that you've mastered Text, we'll explore the Image component — how to display images from local files, remote URLs, and handle different resizing modes.
✍️ Typography Mastered!
You now know how to style text like a pro in React Native. From basic styling to nested inline elements, you've got the tools to create beautiful, readable, and accessible text.