or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

core-styling.mdcss-utilities.mdindex.mdreact-native.mdserver-side-rendering.mdtest-utilities.mdtheming.mdtypescript-integration.md
tile.json

react-native.mddocs/

React Native Support

styled-components provides full React Native integration with platform-specific optimizations and native component support, enabling consistent styling patterns across web and mobile platforms.

React Native styled Function

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:

Basic Native Components

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>
  );
}

Image Components

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>

Input Components

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 CSS Properties

React Native styled-components uses React Native's style properties, which differ from web CSS.

Layout Properties

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);
`;

Text Properties

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'};
`;

Border and Background Properties

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 */
`;

Platform-Specific Styling

Platform Detection

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;
`;

Safe Area Handling

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>
  );
}

List Components

FlatList Styling

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}
    />
  );
}

SectionList Styling

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;
`;

Animation Integration

Animated Components

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>
  );
}

Pressable with Animations

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>
  );
}

Theming in React Native

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>
  );
}

Native-Specific Features

StatusBar Integration

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>
  );
}

Keyboard Handling

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>
  );
}

Performance Considerations

Optimized Components

// 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}
    />
  );
}

Native Style Utilities

toStyleSheet Function

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} />;
}