
Styling in React Native is a crucial aspect of React Native development that determines how your app looks and feels. Unlike web development where you use CSS, React Native uses a JavaScript-based styling system that provides a subset of CSS properties optimized for mobile development.
Introduction to Styling in React Native
React Native styling is based on a subset of CSS, but with important differences:
- Styles are written in JavaScript objects
- CSS properties use camelCase instead of kebab-case
- No cascade (styles don’t inherit like CSS)
- Default layout system is Flexbox
- Dimensions are unitless (density-independent pixels)
Basic Styling Example
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
function MyComponent() {
return (
<View style={styles.container}>
<Text style={styles.title}>Hello, React Native!</Text>
<Text style={styles.subtitle}>Styling is easy</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f0f0f0',
padding: 20,
justifyContent: 'center',
alignItems: 'center',
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: '#333',
marginBottom: 10,
},
subtitle: {
fontSize: 16,
color: '#666',
textAlign: 'center',
},
});
export default MyComponent;
StyleSheet API
The StyleSheet API is the recommended way to create styles in React Native.
Creating Styles
import { StyleSheet } from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
text: {
fontSize: 16,
color: 'black',
},
});
Benefits of StyleSheet.create()
- Performance: Styles are compiled and optimized
- Validation: Props are validated in development
- Reusability: Styles can be reused across components
- Code Organization: Keeps styles organized and maintainable
StyleSheet Methods
// Create styles
const styles = StyleSheet.create({...});
// Flatten style objects
const flattenedStyle = StyleSheet.flatten([styles.base, styles.modifier]);
// Compose styles
const composedStyle = StyleSheet.compose(styles.base, styles.override);
// Get the hairline width (thinnest line possible)
const hairlineWidth = StyleSheet.hairlineWidth;
Inline Styles vs StyleSheet
Inline Styles
function InlineExample() {
return (
<View style={{ backgroundColor: 'red', padding: 10 }}>
<Text style={{ color: 'white', fontSize: 16 }}>Inline Style</Text>
</View>
);
}
StyleSheet (Recommended)
function StyleSheetExample() {
return (
<View style={styles.container}>
<Text style={styles.text}>StyleSheet Style</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'red',
padding: 10,
},
text: {
color: 'white',
fontSize: 16,
},
});
When to Use Each
Use StyleSheet for:
- Reusable styles
- Complex styling
- Performance-critical components
- Maintainable code
Use Inline Styles for:
- Quick prototyping
- Dynamic styles based on props/state
- One-off styling
Common Style Properties
Layout Properties
const layoutStyles = StyleSheet.create({
container: {
// Flexbox
flex: 1,
flexDirection: 'row', // 'row', 'column', 'row-reverse', 'column-reverse'
justifyContent: 'center', // 'flex-start', 'flex-end', 'center', 'space-between', 'space-around', 'space-evenly'
alignItems: 'center', // 'flex-start', 'flex-end', 'center', 'stretch', 'baseline'
alignSelf: 'stretch', // 'auto', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline'
// Dimensions
width: 100,
height: 200,
minWidth: 50,
maxWidth: 300,
minHeight: 100,
maxHeight: 400,
// Position
position: 'absolute', // 'relative', 'absolute'
top: 10,
left: 10,
right: 10,
bottom: 10,
zIndex: 1,
// Margins and Padding
margin: 10,
marginTop: 5,
marginRight: 15,
marginBottom: 5,
marginLeft: 15,
marginHorizontal: 10, // left and right
marginVertical: 5, // top and bottom
padding: 10,
paddingTop: 5,
paddingRight: 15,
paddingBottom: 5,
paddingLeft: 15,
paddingHorizontal: 10,
paddingVertical: 5,
},
});
Text Properties
const textStyles = StyleSheet.create({
title: {
fontSize: 24,
fontWeight: 'bold', // 'normal', 'bold', '100'-'900'
fontStyle: 'italic', // 'normal', 'italic'
fontFamily: 'Arial', // Platform-specific font names
lineHeight: 30,
letterSpacing: 1,
textAlign: 'center', // 'auto', 'left', 'right', 'center', 'justify'
textAlignVertical: 'center', // Android only: 'auto', 'top', 'bottom', 'center'
color: '#333333',
textDecorationLine: 'underline', // 'none', 'underline', 'line-through', 'underline line-through'
textTransform: 'uppercase', // 'none', 'uppercase', 'lowercase', 'capitalize'
},
});
Background and Border Properties
const decorativeStyles = StyleSheet.create({
card: {
backgroundColor: '#ffffff',
// Borders
borderWidth: 1,
borderColor: '#cccccc',
borderTopWidth: 2,
borderRightWidth: 2,
borderBottomWidth: 2,
borderLeftWidth: 2,
borderRadius: 8,
borderTopLeftRadius: 4,
borderTopRightRadius: 4,
borderBottomLeftRadius: 4,
borderBottomRightRadius: 4,
// Border Style
borderStyle: 'solid', // 'solid', 'dotted', 'dashed'
// Shadow (iOS)
shadowColor: '#000000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
// Elevation (Android)
elevation: 4,
// Opacity
opacity: 0.9,
},
});
Color and Gradients
Color Formats
const colorStyles = StyleSheet.create({
// Named colors
red: { backgroundColor: 'red' },
// Hex colors
blue: { backgroundColor: '#0066cc' },
// RGB colors
green: { backgroundColor: 'rgb(0, 255, 0)' },
// RGBA colors
purple: { backgroundColor: 'rgba(128, 0, 128, 0.5)' },
// HSL colors (React Native 0.61+)
orange: { backgroundColor: 'hsl(30, 100%, 50%)' },
// HSLA colors
yellow: { backgroundColor: 'hsla(60, 100%, 50%, 0.8)' },
});
Linear Gradients
For gradients, you’ll need to install react-native-linear-gradient:
npm install react-native-linear-gradient
import LinearGradient from 'react-native-linear-gradient';
function GradientExample() {
return (
<LinearGradient
colors={['#ff7f00', '#ff0f7f']}
style={styles.gradient}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
>
<Text style={styles.gradientText}>Gradient Background</Text>
</LinearGradient>
);
}
const styles = StyleSheet.create({
gradient: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
gradientText: {
color: 'white',
fontSize: 20,
fontWeight: 'bold',
},
});
Dynamic Styling
Conditional Styling
function ConditionalStyling({ isActive, type }) {
return (
<View style={[
styles.button,
isActive && styles.activeButton,
type === 'primary' && styles.primaryButton,
]}>
<Text style={[
styles.buttonText,
isActive && styles.activeText,
]}>
{isActive ? 'Active' : 'Inactive'}
</Text>
</View>
);
}
const styles = StyleSheet.create({
button: {
padding: 10,
borderRadius: 5,
backgroundColor: '#f0f0f0',
},
activeButton: {
backgroundColor: '#007AFF',
},
primaryButton: {
backgroundColor: '#ff6b35',
},
buttonText: {
color: '#333',
textAlign: 'center',
},
activeText: {
color: 'white',
fontWeight: 'bold',
},
});
State-Based Styling
import React, { useState } from 'react';
function StatefulButton() {
const [pressed, setPressed] = useState(false);
return (
<Pressable
style={[
styles.button,
pressed && styles.pressedButton,
]}
onPressIn={() => setPressed(true)}
onPressOut={() => setPressed(false)}
>
<Text style={styles.buttonText}>Press me</Text>
</Pressable>
);
}
const styles = StyleSheet.create({
button: {
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 8,
alignItems: 'center',
},
pressedButton: {
backgroundColor: '#0051d3',
transform: [{ scale: 0.95 }],
},
buttonText: {
color: 'white',
fontWeight: 'bold',
},
});
Theme-Based Styling
const lightTheme = {
background: '#ffffff',
text: '#000000',
primary: '#007AFF',
secondary: '#f0f0f0',
};
const darkTheme = {
background: '#000000',
text: '#ffffff',
primary: '#0A84FF',
secondary: '#1c1c1e',
};
function ThemedComponent({ isDark }) {
const theme = isDark ? darkTheme : lightTheme;
const dynamicStyles = StyleSheet.create({
container: {
backgroundColor: theme.background,
padding: 20,
},
title: {
color: theme.text,
fontSize: 24,
fontWeight: 'bold',
},
button: {
backgroundColor: theme.primary,
padding: 10,
borderRadius: 5,
},
});
return (
<View style={dynamicStyles.container}>
<Text style={dynamicStyles.title}>Themed Component</Text>
<TouchableOpacity style={dynamicStyles.button}>
<Text style={{ color: 'white' }}>Themed Button</Text>
</TouchableOpacity>
</View>
);
}
Responsive Design
Screen Dimensions
import { Dimensions } from 'react-native';
const screenData = Dimensions.get('screen');
const windowData = Dimensions.get('window');
function ResponsiveComponent() {
const [screenData, setScreenData] = useState(Dimensions.get('screen'));
useEffect(() => {
const subscription = Dimensions.addEventListener('change', ({ screen }) => {
setScreenData(screen);
});
return subscription?.remove;
}, []);
const isLandscape = screenData.width > screenData.height;
return (
<View style={[
styles.container,
{ flexDirection: isLandscape ? 'row' : 'column' }
]}>
<Text>Width: {screenData.width}</Text>
<Text>Height: {screenData.height}</Text>
</View>
);
}
Percentage-Based Dimensions
const responsiveStyles = StyleSheet.create({
container: {
width: '100%',
height: '50%',
},
halfWidth: {
width: '50%',
},
quarterHeight: {
height: '25%',
},
});
Platform-Specific Styling
import { Platform } from 'react-native';
const platformStyles = StyleSheet.create({
container: {
paddingTop: Platform.OS === 'ios' ? 20 : 0,
...Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
},
android: {
elevation: 4,
},
}),
},
text: {
fontFamily: Platform.OS === 'ios' ? 'Helvetica' : 'Roboto',
},
});
Transforms and Animations (Brief)
Basic Transforms
const transformStyles = StyleSheet.create({
rotated: {
transform: [{ rotate: '45deg' }],
},
scaled: {
transform: [{ scale: 1.5 }],
},
translated: {
transform: [
{ translateX: 50 },
{ translateY: 100 },
],
},
skewed: {
transform: [{ skewX: '45deg' }],
},
combined: {
transform: [
{ rotate: '45deg' },
{ scale: 1.2 },
{ translateX: 50 },
],
},
});
Advanced Styling Techniques
Style Composition and Inheritance
// Base styles
const baseStyles = StyleSheet.create({
button: {
padding: 10,
borderRadius: 5,
alignItems: 'center',
justifyContent: 'center',
},
text: {
fontSize: 16,
fontWeight: 'bold',
},
});
// Extended styles
const extendedStyles = StyleSheet.create({
primaryButton: {
...baseStyles.button,
backgroundColor: '#007AFF',
},
secondaryButton: {
...baseStyles.button,
backgroundColor: '#f0f0f0',
borderWidth: 1,
borderColor: '#ccc',
},
primaryText: {
...baseStyles.text,
color: 'white',
},
secondaryText: {
...baseStyles.text,
color: '#333',
},
});
Style Functions
const createButtonStyle = (backgroundColor, textColor, size = 'medium') => {
const sizeMap = {
small: { padding: 8, fontSize: 14 },
medium: { padding: 12, fontSize: 16 },
large: { padding: 16, fontSize: 18 },
};
return {
button: {
backgroundColor,
padding: sizeMap[size].padding,
borderRadius: 5,
alignItems: 'center',
},
text: {
color: textColor,
fontSize: sizeMap[size].fontSize,
fontWeight: 'bold',
},
};
};
// Usage
const primaryButtonStyles = createButtonStyle('#007AFF', 'white', 'large');
const secondaryButtonStyles = createButtonStyle('#f0f0f0', '#333', 'medium');
Styled Components Pattern
// Create reusable styled components
const StyledButton = ({ children, variant = 'primary', size = 'medium', ...props }) => {
const buttonStyle = [
styles.baseButton,
styles[`${variant}Button`],
styles[`${size}Button`],
];
const textStyle = [
styles.baseText,
styles[`${variant}Text`],
];
return (
<TouchableOpacity style={buttonStyle} {...props}>
<Text style={textStyle}>{children}</Text>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
baseButton: {
borderRadius: 5,
alignItems: 'center',
justifyContent: 'center',
},
primaryButton: {
backgroundColor: '#007AFF',
},
secondaryButton: {
backgroundColor: '#f0f0f0',
borderWidth: 1,
borderColor: '#ccc',
},
smallButton: {
padding: 8,
},
mediumButton: {
padding: 12,
},
largeButton: {
padding: 16,
},
baseText: {
fontWeight: 'bold',
},
primaryText: {
color: 'white',
},
secondaryText: {
color: '#333',
},
});
Performance Considerations
Optimizing Styles
// ❌ Bad: Creating styles in render
function BadComponent() {
return (
<View style={{ backgroundColor: 'red', padding: 10 }}>
<Text style={{ color: 'white' }}>Bad</Text>
</View>
);
}
// ✅ Good: Using StyleSheet
const styles = StyleSheet.create({
container: {
backgroundColor: 'red',
padding: 10,
},
text: {
color: 'white',
},
});
function GoodComponent() {
return (
<View style={styles.container}>
<Text style={styles.text}>Good</Text>
</View>
);
}
Memoizing Dynamic Styles
import React, { useMemo } from 'react';
function OptimizedComponent({ backgroundColor, textColor }) {
const dynamicStyles = useMemo(() => ({
container: {
backgroundColor,
padding: 20,
},
text: {
color: textColor,
},
}), [backgroundColor, textColor]);
return (
<View style={[styles.baseContainer, dynamicStyles.container]}>
<Text style={[styles.baseText, dynamicStyles.text]}>
Optimized Dynamic Styling
</Text>
</View>
);
}
const styles = StyleSheet.create({
baseContainer: {
borderRadius: 5,
alignItems: 'center',
},
baseText: {
fontSize: 16,
fontWeight: 'bold',
},
});
Common Styling Patterns
Card Component
function Card({ children, title }) {
return (
<View style={styles.card}>
{title && <Text style={styles.cardTitle}>{title}</Text>}
<View style={styles.cardContent}>
{children}
</View>
</View>
);
}
const styles = StyleSheet.create({
card: {
backgroundColor: 'white',
borderRadius: 8,
padding: 16,
marginVertical: 8,
marginHorizontal: 16,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
cardTitle: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 12,
color: '#333',
},
cardContent: {
// Content styling
},
});
Avatar Component
function Avatar({ source, size = 50, name }) {
const initials = name ? name.split(' ').map(n => n[0]).join('').toUpperCase() : '';
const avatarStyle = {
width: size,
height: size,
borderRadius: size / 2,
};
return (
<View style={[styles.avatarContainer, avatarStyle]}>
{source ? (
<Image source={source} style={[styles.avatarImage, avatarStyle]} />
) : (
<Text style={[styles.avatarText, { fontSize: size * 0.4 }]}>
{initials}
</Text>
)}
</View>
);
}
const styles = StyleSheet.create({
avatarContainer: {
backgroundColor: '#ccc',
alignItems: 'center',
justifyContent: 'center',
},
avatarImage: {
resizeMode: 'cover',
},
avatarText: {
color: 'white',
fontWeight: 'bold',
},
});
Badge Component
function Badge({ count, children, maxCount = 99 }) {
const displayCount = count > maxCount ? `${maxCount}+` : count.toString();
return (
<View style={styles.badgeContainer}>
{children}
{count > 0 && (
<View style={styles.badge}>
<Text style={styles.badgeText}>{displayCount}</Text>
</View>
)}
</View>
);
}
const styles = StyleSheet.create({
badgeContainer: {
position: 'relative',
},
badge: {
position: 'absolute',
top: -8,
right: -8,
backgroundColor: 'red',
borderRadius: 12,
minWidth: 24,
height: 24,
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 6,
},
badgeText: {
color: 'white',
fontSize: 12,
fontWeight: 'bold',
},
});
Debugging Styles
Inspector and Debug Tools
// Enable layout inspection in development
import { LogBox } from 'react-native';
if (__DEV__) {
LogBox.ignoreLogs(['Warning: ...']);
}
// Add border for debugging layout
const debugStyles = StyleSheet.create({
debugBorder: {
borderWidth: 1,
borderColor: 'red',
},
});
Common Styling Issues and Solutions
// Issue: Text not showing
// Solution: Ensure parent has proper dimensions
const fixedStyles = StyleSheet.create({
container: {
flex: 1, // or specific height/width
},
text: {
// Text will now be visible
},
});
// Issue: Flexbox not working as expected
// Solution: Check flex container properties
const flexFixStyles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column', // Explicitly set direction
},
item: {
flex: 1, // Will take up available space
},
});
Summary
React Native styling provides a powerful and flexible way to create beautiful mobile applications. Key takeaways:
- Use StyleSheet.create() for optimal performance and organization
- Flexbox is the primary layout system
- Conditional styling enables dynamic UIs
- Platform-specific styles ensure native look and feel
- Performance considerations are important for smooth UIs
- Reusable components promote consistent design
Understanding these styling concepts will help you create polished, professional-looking React Native applications. In the next chapter, we’ll dive deeper into responsive layouts and Flexbox to create adaptable interfaces for different screen sizes!
Related Articles:
- React Native vs Flutter in 2024: A Detailed Comparison
- Top 10 React Native Libraries You Must Know in 2024
- React vs React Native: A Deep Dive into Key Differences
- How to Set Up Navigation in React Native : Step-by-Step Guide
- What is Axios? Fetch vs Axios: What’s the Difference?
- React Native Environment Setup: A Beginner’s Step-by-Step Guide
- React Native Web: A Step-by-Step Guide to Cross-Platform Development