A framework for building native apps using React
Overall
score
100%
Evaluation — 100%
↑ 1.06xAgent success when using this tile
React Native provides custom React hooks that integrate with platform APIs and device capabilities, enabling reactive and responsive user interfaces.
npm install react-nativeReact hook for getting current window dimensions with automatic updates on orientation changes and device rotation.
// ESM
import {useWindowDimensions} from 'react-native';
// CommonJS
const {useWindowDimensions} = require('react-native');
// Basic usage
function ResponsiveComponent() {
const {width, height, scale, fontScale} = useWindowDimensions();
const isLandscape = width > height;
const isTablet = width >= 768;
return (
<View style={{
width: width * 0.9,
height: isTablet ? height * 0.7 : height * 0.5,
backgroundColor: isLandscape ? 'lightblue' : 'lightcoral',
}}>
<Text>
Window: {width} x {height}
</Text>
<Text>Scale: {scale}</Text>
<Text>Font Scale: {fontScale}</Text>
<Text>Orientation: {isLandscape ? 'Landscape' : 'Portrait'}</Text>
<Text>Device: {isTablet ? 'Tablet' : 'Phone'}</Text>
</View>
);
}
// Responsive layout hook
function useResponsiveLayout() {
const {width, height} = useWindowDimensions();
const breakpoints = {
xs: 0,
sm: 576,
md: 768,
lg: 992,
xl: 1200,
};
const getBreakpoint = () => {
if (width >= breakpoints.xl) return 'xl';
if (width >= breakpoints.lg) return 'lg';
if (width >= breakpoints.md) return 'md';
if (width >= breakpoints.sm) return 'sm';
return 'xs';
};
return {
width,
height,
breakpoint: getBreakpoint(),
isPhone: width < breakpoints.md,
isTablet: width >= breakpoints.md && width < breakpoints.lg,
isDesktop: width >= breakpoints.lg,
isLandscape: width > height,
isPortrait: height >= width,
};
}
// Usage with responsive layout
function ResponsiveGrid() {
const {breakpoint, isTablet} = useResponsiveLayout();
const getColumns = () => {
switch (breakpoint) {
case 'xl': return 4;
case 'lg': return 3;
case 'md': return 2;
default: return 1;
}
};
const columns = getColumns();
const itemWidth = `${100 / columns}%`;
return (
<View style={styles.container}>
<Text>Current breakpoint: {breakpoint}</Text>
<Text>Columns: {columns}</Text>
<View style={styles.grid}>
{Array.from({length: 12}, (_, i) => (
<View
key={i}
style={[styles.gridItem, {width: itemWidth}]}
>
<Text>Item {i + 1}</Text>
</View>
))}
</View>
</View>
);
}
// Dynamic text sizing based on screen size
function useResponsiveText() {
const {width, fontScale} = useWindowDimensions();
const getTextSize = (baseSize) => {
const screenScale = width / 375; // Base iPhone screen width
const scaledSize = baseSize * screenScale;
// Apply font scale preference
return scaledSize * fontScale;
};
return {
small: getTextSize(12),
body: getTextSize(16),
title: getTextSize(20),
heading: getTextSize(24),
display: getTextSize(32),
};
}
// Responsive text component
function ResponsiveText({size = 'body', children, style, ...props}) {
const textSizes = useResponsiveText();
return (
<Text
style={[{fontSize: textSizes[size]}, style]}
{...props}
>
{children}
</Text>
);
}
// Adaptive component based on dimensions
function AdaptiveModal({visible, children, onClose}) {
const {width, height, isTablet} = useResponsiveLayout();
const modalStyle = isTablet ? {
width: Math.min(width * 0.8, 600),
height: Math.min(height * 0.8, 800),
alignSelf: 'center',
marginTop: height * 0.1,
} : {
width: '100%',
height: '100%',
};
return (
<Modal
visible={visible}
animationType="slide"
presentationStyle={isTablet ? 'formSheet' : 'fullScreen'}
onRequestClose={onClose}
>
<View style={[styles.modalContainer, modalStyle]}>
{children}
</View>
</Modal>
);
}
// Keyboard-aware layout with window dimensions
function KeyboardAwareLayout({children}) {
const {height} = useWindowDimensions();
const [keyboardHeight, setKeyboardHeight] = useState(0);
useEffect(() => {
const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', (e) => {
setKeyboardHeight(e.endCoordinates.height);
});
const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {
setKeyboardHeight(0);
});
return () => {
keyboardDidShowListener.remove();
keyboardDidHideListener.remove();
};
}, []);
const availableHeight = height - keyboardHeight;
return (
<View style={{height: availableHeight}}>
{children}
</View>
);
}interface WindowDimensions {
width: number;
height: number;
scale: number;
fontScale: number;
}
interface useWindowDimensionsStatic {
(): WindowDimensions;
}
// Custom responsive layout types
interface ResponsiveLayout extends WindowDimensions {
breakpoint: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
isPhone: boolean;
isTablet: boolean;
isDesktop: boolean;
isLandscape: boolean;
isPortrait: boolean;
}
interface ResponsiveTextSizes {
small: number;
body: number;
title: number;
heading: number;
display: number;
}React hook for accessing the current color scheme (light/dark mode) with automatic updates when the system appearance changes.
import {useColorScheme} from 'react-native';
// Basic color scheme detection
function ThemedComponent() {
const colorScheme = useColorScheme();
const isDark = colorScheme === 'dark';
const styles = StyleSheet.create({
container: {
backgroundColor: isDark ? '#000000' : '#ffffff',
flex: 1,
},
text: {
color: isDark ? '#ffffff' : '#000000',
},
});
return (
<View style={styles.container}>
<Text style={styles.text}>
Current theme: {colorScheme || 'system default'}
</Text>
</View>
);
}
// Theme provider using color scheme
function ThemeProvider({children}) {
const colorScheme = useColorScheme();
const theme = {
colors: {
primary: colorScheme === 'dark' ? '#bb86fc' : '#6200ee',
background: colorScheme === 'dark' ? '#121212' : '#ffffff',
surface: colorScheme === 'dark' ? '#1e1e1e' : '#f5f5f5',
text: colorScheme === 'dark' ? '#ffffff' : '#000000',
textSecondary: colorScheme === 'dark' ? '#b3b3b3' : '#666666',
border: colorScheme === 'dark' ? '#333333' : '#e0e0e0',
error: colorScheme === 'dark' ? '#cf6679' : '#b00020',
success: colorScheme === 'dark' ? '#4caf50' : '#388e3c',
warning: colorScheme === 'dark' ? '#ff9800' : '#f57c00',
},
spacing: {
xs: 4,
sm: 8,
md: 16,
lg: 24,
xl: 32,
},
typography: {
small: 12,
body: 16,
subtitle: 18,
title: 20,
headline: 24,
},
isDark: colorScheme === 'dark',
};
return (
<ThemeContext.Provider value={theme}>
{children}
</ThemeContext.Provider>
);
}
// Custom hook for theme
function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within ThemeProvider');
}
return context;
}
// Themed components
function ThemedCard({title, children, style}) {
const theme = useTheme();
const cardStyles = StyleSheet.create({
card: {
backgroundColor: theme.colors.surface,
borderRadius: 8,
padding: theme.spacing.md,
marginVertical: theme.spacing.sm,
borderWidth: 1,
borderColor: theme.colors.border,
...Platform.select({
ios: {
shadowColor: theme.colors.text,
shadowOffset: {width: 0, height: 2},
shadowOpacity: theme.isDark ? 0.3 : 0.1,
shadowRadius: 4,
},
android: {
elevation: theme.isDark ? 8 : 4,
},
}),
},
title: {
fontSize: theme.typography.title,
fontWeight: 'bold',
color: theme.colors.text,
marginBottom: theme.spacing.sm,
},
});
return (
<View style={[cardStyles.card, style]}>
{title && <Text style={cardStyles.title}>{title}</Text>}
{children}
</View>
);
}
// Status bar that adapts to color scheme
function AdaptiveStatusBar() {
const colorScheme = useColorScheme();
return (
<StatusBar
barStyle={colorScheme === 'dark' ? 'light-content' : 'dark-content'}
backgroundColor={colorScheme === 'dark' ? '#000000' : '#ffffff'}
/>
);
}
// Navigation theme based on color scheme
function useNavigationTheme() {
const colorScheme = useColorScheme();
const lightTheme = {
colors: {
primary: '#007AFF',
background: '#ffffff',
card: '#ffffff',
text: '#000000',
border: '#e0e0e0',
notification: '#ff3b30',
},
};
const darkTheme = {
colors: {
primary: '#0A84FF',
background: '#000000',
card: '#1c1c1e',
text: '#ffffff',
border: '#333333',
notification: '#ff453a',
},
};
return colorScheme === 'dark' ? darkTheme : lightTheme;
}
// Image that adapts to color scheme
function AdaptiveImage({lightSource, darkSource, ...props}) {
const colorScheme = useColorScheme();
const source = colorScheme === 'dark' ? darkSource : lightSource;
return <Image source={source} {...props} />;
}
// Color scheme preference hook
function useColorSchemePreference() {
const systemColorScheme = useColorScheme();
const [userPreference, setUserPreference] = useState('system');
const effectiveColorScheme = userPreference === 'system'
? systemColorScheme
: userPreference;
const setColorScheme = (scheme) => {
setUserPreference(scheme);
// Save to AsyncStorage or preferences
};
return {
colorScheme: effectiveColorScheme,
userPreference,
systemColorScheme,
setColorScheme,
};
}
// Settings component for color scheme
function ColorSchemeSettings() {
const {userPreference, setColorScheme} = useColorSchemePreference();
const options = [
{label: 'System', value: 'system'},
{label: 'Light', value: 'light'},
{label: 'Dark', value: 'dark'},
];
return (
<View>
<Text style={styles.settingsTitle}>Appearance</Text>
{options.map(option => (
<TouchableOpacity
key={option.value}
style={styles.optionRow}
onPress={() => setColorScheme(option.value)}
>
<Text style={styles.optionText}>{option.label}</Text>
{userPreference === option.value && (
<Text style={styles.checkmark}>✓</Text>
)}
</TouchableOpacity>
))}
</View>
);
}
// Component that renders differently based on theme
function ConditionalContent() {
const colorScheme = useColorScheme();
if (colorScheme === 'dark') {
return (
<View style={styles.darkContainer}>
<Text style={styles.darkText}>Dark mode content</Text>
<Image source={require('./assets/dark-logo.png')} />
</View>
);
}
return (
<View style={styles.lightContainer}>
<Text style={styles.lightText}>Light mode content</Text>
<Image source={require('./assets/light-logo.png')} />
</View>
);
}
// Hook for creating adaptive styles
function useAdaptiveStyles(createStyles) {
const colorScheme = useColorScheme();
return useMemo(() => {
return createStyles(colorScheme === 'dark');
}, [colorScheme, createStyles]);
}
// Usage with adaptive styles
function AdaptiveStyledComponent() {
const styles = useAdaptiveStyles((isDark) => StyleSheet.create({
container: {
backgroundColor: isDark ? '#1a1a1a' : '#f8f9fa',
padding: 20,
},
text: {
color: isDark ? '#e0e0e0' : '#333333',
fontSize: 16,
},
button: {
backgroundColor: isDark ? '#333333' : '#007AFF',
padding: 12,
borderRadius: 8,
},
buttonText: {
color: isDark ? '#ffffff' : '#ffffff',
textAlign: 'center',
},
}));
return (
<View style={styles.container}>
<Text style={styles.text}>Adaptive styling example</Text>
<TouchableOpacity style={styles.button}>
<Text style={styles.buttonText}>Button</Text>
</TouchableOpacity>
</View>
);
}type ColorSchemeName = 'light' | 'dark' | null;
interface useColorSchemeStatic {
(): ColorSchemeName;
}
// Theme-related types
interface ThemeColors {
primary: string;
background: string;
surface: string;
text: string;
textSecondary: string;
border: string;
error: string;
success: string;
warning: string;
}
interface ThemeSpacing {
xs: number;
sm: number;
md: number;
lg: number;
xl: number;
}
interface ThemeTypography {
small: number;
body: number;
subtitle: number;
title: number;
headline: number;
}
interface Theme {
colors: ThemeColors;
spacing: ThemeSpacing;
typography: ThemeTypography;
isDark: boolean;
}
interface ColorSchemePreference {
colorScheme: ColorSchemeName;
userPreference: 'system' | 'light' | 'dark';
systemColorScheme: ColorSchemeName;
setColorScheme: (scheme: 'system' | 'light' | 'dark') => void;
}// Device orientation hook
function useDeviceOrientation() {
const {width, height} = useWindowDimensions();
const orientation = width > height ? 'landscape' : 'portrait';
return {
orientation,
isLandscape: orientation === 'landscape',
isPortrait: orientation === 'portrait',
width,
height,
};
}
// Safe area hook
function useSafeArea() {
const [safeArea, setSafeArea] = useState({top: 0, bottom: 0, left: 0, right: 0});
useEffect(() => {
// Get safe area insets (would need native implementation)
if (Platform.OS === 'ios') {
// iOS safe area detection
setSafeArea({top: 44, bottom: 34, left: 0, right: 0});
} else {
// Android safe area detection
setSafeArea({top: 24, bottom: 0, left: 0, right: 0});
}
}, []);
return safeArea;
}
// Keyboard height hook
function useKeyboardHeight() {
const [keyboardHeight, setKeyboardHeight] = useState(0);
useEffect(() => {
const keyboardDidShowListener = Keyboard.addListener(
'keyboardDidShow',
(e) => setKeyboardHeight(e.endCoordinates.height)
);
const keyboardDidHideListener = Keyboard.addListener(
'keyboardDidHide',
() => setKeyboardHeight(0)
);
return () => {
keyboardDidShowListener.remove();
keyboardDidHideListener.remove();
};
}, []);
return keyboardHeight;
}
// Network status hook
function useNetworkStatus() {
const [isConnected, setIsConnected] = useState(true);
const [connectionType, setConnectionType] = useState('unknown');
useEffect(() => {
// Network status monitoring (would need NetInfo library)
const unsubscribe = NetInfo?.addEventListener(state => {
setIsConnected(state.isConnected);
setConnectionType(state.type);
});
return () => unsubscribe?.();
}, []);
return {
isConnected,
connectionType,
isOffline: !isConnected,
};
}
// App state hook
function useAppState() {
const [appState, setAppState] = useState(AppState.currentState);
useEffect(() => {
const subscription = AppState.addEventListener('change', setAppState);
return () => subscription.remove();
}, []);
return {
appState,
isActive: appState === 'active',
isBackground: appState === 'background',
isInactive: appState === 'inactive',
};
}
// Combined device info hook
function useDeviceInfo() {
const dimensions = useWindowDimensions();
const colorScheme = useColorScheme();
const orientation = useDeviceOrientation();
const safeArea = useSafeArea();
const keyboardHeight = useKeyboardHeight();
const appState = useAppState();
return {
...dimensions,
colorScheme,
...orientation,
safeArea,
keyboardHeight,
...appState,
platform: Platform.OS,
platformVersion: Platform.Version,
};
}
// Usage example
function DeviceInfoDisplay() {
const deviceInfo = useDeviceInfo();
return (
<ScrollView style={styles.container}>
<Text style={styles.title}>Device Information</Text>
<View style={styles.section}>
<Text style={styles.sectionTitle}>Dimensions</Text>
<Text>Width: {deviceInfo.width}</Text>
<Text>Height: {deviceInfo.height}</Text>
<Text>Scale: {deviceInfo.scale}</Text>
<Text>Font Scale: {deviceInfo.fontScale}</Text>
</View>
<View style={styles.section}>
<Text style={styles.sectionTitle}>Orientation</Text>
<Text>Current: {deviceInfo.orientation}</Text>
<Text>Is Landscape: {deviceInfo.isLandscape.toString()}</Text>
</View>
<View style={styles.section}>
<Text style={styles.sectionTitle}>Appearance</Text>
<Text>Color Scheme: {deviceInfo.colorScheme || 'system'}</Text>
</View>
<View style={styles.section}>
<Text style={styles.sectionTitle}>Platform</Text>
<Text>OS: {deviceInfo.platform}</Text>
<Text>Version: {deviceInfo.platformVersion}</Text>
</View>
<View style={styles.section}>
<Text style={styles.sectionTitle}>App State</Text>
<Text>Current: {deviceInfo.appState}</Text>
<Text>Is Active: {deviceInfo.isActive.toString()}</Text>
</View>
<View style={styles.section}>
<Text style={styles.sectionTitle}>Keyboard</Text>
<Text>Height: {deviceInfo.keyboardHeight}</Text>
</View>
</ScrollView>
);
}This comprehensive React hooks documentation provides developers with all the tools needed to create reactive, responsive user interfaces that adapt to device capabilities and user preferences in React Native applications.
Install with Tessl CLI
npx tessl i tessl/npm-react-native@1000.0.0docs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10