styled-components provides full React Native integration with platform-specific optimizations and native component support, enabling consistent styling patterns across web and mobile platforms.
The React Native version of styled-components provides the same API but optimized for React Native components and styling constraints.
// Import from 'styled-components/native'
declare const styled: {
<Target extends React.ComponentType<any>>(target: Target): NativeStyledInstance<Target>;
// Native component shortcuts (complete list)
ActivityIndicator: NativeStyledInstance<typeof ActivityIndicator>;
Button: NativeStyledInstance<typeof Button>;
DatePickerIOS: NativeStyledInstance<typeof DatePickerIOS>;
DrawerLayoutAndroid: NativeStyledInstance<typeof DrawerLayoutAndroid>;
FlatList: NativeStyledInstance<typeof FlatList>;
Image: NativeStyledInstance<typeof Image>;
ImageBackground: NativeStyledInstance<typeof ImageBackground>;
KeyboardAvoidingView: NativeStyledInstance<typeof KeyboardAvoidingView>;
Modal: NativeStyledInstance<typeof Modal>;
Pressable: NativeStyledInstance<typeof Pressable>;
ProgressBarAndroid: NativeStyledInstance<typeof ProgressBarAndroid>;
ProgressViewIOS: NativeStyledInstance<typeof ProgressViewIOS>;
RefreshControl: NativeStyledInstance<typeof RefreshControl>;
SafeAreaView: NativeStyledInstance<typeof SafeAreaView>;
ScrollView: NativeStyledInstance<typeof ScrollView>;
SectionList: NativeStyledInstance<typeof SectionList>;
Slider: NativeStyledInstance<typeof Slider>;
Switch: NativeStyledInstance<typeof Switch>;
Text: NativeStyledInstance<typeof Text>;
TextInput: NativeStyledInstance<typeof TextInput>;
TouchableHighlight: NativeStyledInstance<typeof TouchableHighlight>;
TouchableOpacity: NativeStyledInstance<typeof TouchableOpacity>;
View: NativeStyledInstance<typeof View>;
VirtualizedList: NativeStyledInstance<typeof VirtualizedList>;
};
interface NativeStyledInstance<Target> {
(strings: TemplateStringsArray, ...interpolations: Interpolation<any>[]): StyledNativeComponent<Target>;
attrs<AttrsProps>(attrs: Attrs<AttrsProps>): NativeStyledInstance<Target>;
withConfig(config: StyledOptions<'native', any>): NativeStyledInstance<Target>;
}Usage Examples:
import styled from 'styled-components/native';
// Basic View styling
const Container = styled.View`
flex: 1;
background-color: #f5f5f5;
padding: 20px;
`;
// Text styling
const Title = styled.Text`
font-size: 24px;
font-weight: bold;
color: #333;
margin-bottom: 16px;
`;
// TouchableOpacity styling
const Button = styled.TouchableOpacity`
background-color: #007bff;
padding: 12px 24px;
border-radius: 8px;
align-items: center;
`;
const ButtonText = styled.Text`
color: white;
font-size: 16px;
font-weight: 600;
`;
// Usage
function App() {
return (
<Container>
<Title>Welcome to React Native</Title>
<Button onPress={() => console.log('Pressed!')}>
<ButtonText>Press Me</ButtonText>
</Button>
</Container>
);
}const ProfileImage = styled.Image`
width: 100px;
height: 100px;
border-radius: 50px;
border-width: 3px;
border-color: #007bff;
`;
const BackgroundContainer = styled.ImageBackground`
flex: 1;
justify-content: center;
align-items: center;
`;
const Overlay = styled.View`
background-color: rgba(0, 0, 0, 0.5);
padding: 20px;
border-radius: 12px;
`;
// Usage
<BackgroundContainer source={{ uri: 'https://example.com/bg.jpg' }}>
<Overlay>
<ProfileImage source={{ uri: 'https://example.com/avatar.jpg' }} />
</Overlay>
</BackgroundContainer>const Input = styled.TextInput<{ hasError?: boolean }>`
border-width: 1px;
border-color: ${props => props.hasError ? '#dc3545' : '#ced4da'};
border-radius: 8px;
padding: 12px 16px;
font-size: 16px;
background-color: white;
margin-bottom: 16px;
`;
const ErrorText = styled.Text`
color: #dc3545;
font-size: 14px;
margin-top: -12px;
margin-bottom: 16px;
`;
// Usage
function LoginForm() {
const [email, setEmail] = React.useState('');
const [hasError, setHasError] = React.useState(false);
return (
<View>
<Input
value={email}
onChangeText={setEmail}
placeholder="Enter email"
hasError={hasError}
keyboardType="email-address"
/>
{hasError && <ErrorText>Please enter a valid email</ErrorText>}
</View>
);
}React Native styled-components uses React Native's style properties, which differ from web CSS.
const FlexContainer = styled.View`
flex: 1;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 16px;
`;
const FlexItem = styled.View<{ flex?: number }>`
flex: ${props => props.flex || 0};
margin: 8px;
background-color: #e9ecef;
`;
// Position properties
const AbsoluteView = styled.View`
position: absolute;
top: 0;
right: 0;
width: 50px;
height: 50px;
background-color: rgba(255, 0, 0, 0.8);
`;const StyledText = styled.Text`
font-family: System;
font-size: 16px;
font-weight: 400;
line-height: 24px;
color: #212529;
text-align: center;
text-decoration-line: underline;
text-transform: uppercase;
`;
// Platform-specific text styling
const PlatformText = styled.Text`
font-family: ${Platform.OS === 'ios' ? 'San Francisco' : 'Roboto'};
font-size: ${Platform.OS === 'ios' ? '17px' : '16px'};
`;const BorderedView = styled.View`
border-width: 2px;
border-color: #007bff;
border-style: solid;
border-radius: 12px;
background-color: white;
/* Individual border sides */
border-top-width: 3px;
border-top-color: #28a745;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
`;
const GradientLikeView = styled.View`
background-color: #007bff;
/* Note: True gradients require react-native-linear-gradient */
`;import { Platform } from 'react-native';
const PlatformSpecificView = styled.View`
padding: 16px;
${Platform.OS === 'ios' && `
shadow-color: #000;
shadow-offset: 0px 2px;
shadow-opacity: 0.25;
shadow-radius: 3.84px;
`}
${Platform.OS === 'android' && `
elevation: 5;
`}
`;
// Using Platform.select()
const ResponsiveText = styled.Text`
font-size: ${Platform.select({
ios: 17,
android: 16,
default: 16
})}px;
`;import { useSafeAreaInsets } from 'react-native-safe-area-context';
const SafeContainer = styled.View<{ insets: any }>`
flex: 1;
padding-top: ${props => props.insets.top}px;
padding-bottom: ${props => props.insets.bottom}px;
padding-left: ${props => props.insets.left}px;
padding-right: ${props => props.insets.right}px;
`;
// Usage
function SafeApp() {
const insets = useSafeAreaInsets();
return (
<SafeContainer insets={insets}>
<AppContent />
</SafeContainer>
);
}const StyledFlatList = styled.FlatList`
flex: 1;
background-color: #f8f9fa;
`;
const ListItem = styled.TouchableOpacity`
padding: 16px;
border-bottom-width: 1px;
border-bottom-color: #e9ecef;
flex-direction: row;
align-items: center;
`;
const ItemText = styled.Text`
flex: 1;
font-size: 16px;
color: #333;
`;
const ItemBadge = styled.View`
background-color: #007bff;
border-radius: 12px;
padding: 4px 8px;
`;
const BadgeText = styled.Text`
color: white;
font-size: 12px;
font-weight: bold;
`;
// Usage
function ItemList({ data }) {
const renderItem = ({ item }) => (
<ListItem>
<ItemText>{item.title}</ItemText>
<ItemBadge>
<BadgeText>{item.count}</BadgeText>
</ItemBadge>
</ListItem>
);
return (
<StyledFlatList
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
);
}const StyledSectionList = styled.SectionList`
flex: 1;
background-color: white;
`;
const SectionHeader = styled.View`
background-color: #f8f9fa;
padding: 12px 16px;
border-bottom-width: 1px;
border-bottom-color: #e9ecef;
`;
const SectionTitle = styled.Text`
font-size: 18px;
font-weight: bold;
color: #495057;
`;
const SectionItem = styled.TouchableOpacity`
padding: 16px;
border-bottom-width: 1px;
border-bottom-color: #f1f3f4;
`;import { Animated } from 'react-native';
// Create styled animated components
const AnimatedView = styled(Animated.View)`
flex: 1;
background-color: #007bff;
`;
const AnimatedText = styled(Animated.Text)`
font-size: 18px;
color: white;
text-align: center;
`;
// Usage with animations
function AnimatedComponent() {
const fadeAnim = React.useRef(new Animated.Value(0)).current;
React.useEffect(() => {
Animated.timing(fadeAnim, {
toValue: 1,
duration: 1000,
useNativeDriver: true,
}).start();
}, [fadeAnim]);
return (
<AnimatedView style={{ opacity: fadeAnim }}>
<AnimatedText>Fading In!</AnimatedText>
</AnimatedView>
);
}const AnimatedPressable = styled.Pressable<{ pressed: boolean }>`
background-color: ${props => props.pressed ? '#0056b3' : '#007bff'};
padding: 16px;
border-radius: 8px;
transform: scale(${props => props.pressed ? 0.95 : 1});
`;
// Usage
function AnimatedButton({ onPress, children }) {
return (
<AnimatedPressable onPress={onPress}>
{({ pressed }) => (
<AnimatedPressable pressed={pressed}>
<Text>{children}</Text>
</AnimatedPressable>
)}
</AnimatedPressable>
);
}React Native styled-components supports the same theming system as web.
import styled, { ThemeProvider } from 'styled-components/native';
const nativeTheme = {
colors: {
primary: '#007bff',
background: '#ffffff',
surface: '#f8f9fa',
text: '#212529',
border: '#dee2e6',
},
spacing: {
xs: 4,
sm: 8,
md: 16,
lg: 24,
xl: 32,
},
fonts: {
regular: Platform.OS === 'ios' ? 'San Francisco' : 'Roboto',
bold: Platform.OS === 'ios' ? 'San Francisco-Bold' : 'Roboto-Bold',
},
};
const ThemedContainer = styled.View`
flex: 1;
background-color: ${props => props.theme.colors.background};
padding: ${props => props.theme.spacing.md}px;
`;
const ThemedText = styled.Text`
color: ${props => props.theme.colors.text};
font-family: ${props => props.theme.fonts.regular};
`;
// Usage
function ThemedApp() {
return (
<ThemeProvider theme={nativeTheme}>
<ThemedContainer>
<ThemedText>Themed React Native App</ThemedText>
</ThemedContainer>
</ThemeProvider>
);
}import { StatusBar } from 'react-native';
const StatusBarView = styled.View<{ backgroundColor: string }>`
background-color: ${props => props.backgroundColor};
height: ${Platform.OS === 'ios' ? 44 : StatusBar.currentHeight || 0}px;
`;
const AppContainer = styled.View`
flex: 1;
background-color: white;
`;
function AppWithStatusBar() {
return (
<AppContainer>
<StatusBarView backgroundColor="#007bff" />
<StatusBar barStyle="light-content" backgroundColor="#007bff" />
<AppContent />
</AppContainer>
);
}const KeyboardAwareContainer = styled.KeyboardAvoidingView`
flex: 1;
background-color: white;
`;
const FormContainer = styled.View`
padding: 16px;
justify-content: center;
`;
function KeyboardForm() {
return (
<KeyboardAwareContainer
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
<FormContainer>
<Input placeholder="Username" />
<Input placeholder="Password" secureTextEntry />
<Button>Login</Button>
</FormContainer>
</KeyboardAwareContainer>
);
}// Memoized styled components for performance
const MemoizedListItem = React.memo(styled.TouchableOpacity`
padding: 16px;
border-bottom-width: 1px;
border-bottom-color: #e9ecef;
`);
// Use getItemLayout for better FlatList performance
const ITEM_HEIGHT = 80;
const OptimizedFlatList = styled.FlatList`
flex: 1;
`;
function PerformantList({ data }) {
const getItemLayout = React.useCallback(
(data, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
}),
[]
);
return (
<OptimizedFlatList
data={data}
getItemLayout={getItemLayout}
removeClippedSubviews={true}
maxToRenderPerBatch={10}
windowSize={10}
/>
);
}Converts styled-components CSS rules to React Native StyleSheet objects for direct use in native styling.
function toStyleSheet(rules: RuleSet<object>): ReactNative.ViewStyle | ReactNative.TextStyle | ReactNative.ImageStyle;Usage Examples:
import { css, toStyleSheet } from 'styled-components/native';
// Create reusable style rules
const buttonStyles = css`
background-color: #007bff;
padding: 12px 24px;
border-radius: 8px;
align-items: center;
`;
// Convert to React Native StyleSheet
const buttonStyleSheet = toStyleSheet(buttonStyles);
// Use directly in React Native components
function NativeButton({ children, ...props }) {
return (
<TouchableOpacity style={buttonStyleSheet} {...props}>
<Text style={{ color: 'white', fontWeight: '600' }}>
{children}
</Text>
</TouchableOpacity>
);
}
// Combine with dynamic styles
function DynamicStyledComponent({ variant, ...props }) {
const baseStyles = css`
padding: 16px;
border-radius: 4px;
`;
const variantStyles = css`
background-color: ${variant === 'primary' ? '#007bff' : '#6c757d'};
`;
const combinedStyles = [
toStyleSheet(baseStyles),
toStyleSheet(variantStyles),
];
return <View style={combinedStyles} {...props} />;
}