This document provides detailed documentation for the theme hooks used in the Fynd Commerce App. These hooks provide a clean, type-safe interface for accessing and using theme data.
The theme system provides two main hooks:
useCustomTheme- Access theme data directly in componentsuseThemedStyles- Create themed styles with memoization
import {useCustomTheme} from '../shared/hooks/use-custom-theme';The useCustomTheme hook provides direct access to the current theme configuration, including colors, typography, spacing, and layout properties.
CustomTheme: The current theme configuration object
Error: If used outside of ThemeProvider contextError: If theme is missing required properties
import {useCustomTheme} from '../shared/hooks/use-custom-theme';
const MyComponent = () => {
const theme = useCustomTheme();
return (
<View style={{backgroundColor: theme.color.primaryColor}}>
<Text style={{color: theme.color.textBody}}>Hello World</Text>
</View>
);
};const TypographyExample = () => {
const theme = useCustomTheme();
return (
<View>
<Text
style={{
fontSize: theme.typography.fontSize.heading,
fontWeight: theme.typography.fontWeight.bold,
color: theme.color.textHeading,
lineHeight: theme.typography.lineHeight.heading,
}}>
Heading Text
</Text>
<Text
style={{
fontSize: theme.typography.fontSize.base,
fontWeight: theme.typography.fontWeight.regular,
color: theme.color.textBody,
lineHeight: theme.typography.lineHeight.base,
}}>
Body Text
</Text>
</View>
);
};const SpacingExample = () => {
const theme = useCustomTheme();
return (
<View
style={{
padding: theme.spacing.md,
margin: theme.spacing.base,
gap: theme.spacing.sm,
}}>
<Text>Content with themed spacing</Text>
</View>
);
};const ColorVariantsExample = () => {
const theme = useCustomTheme();
return (
<View>
{/* Primary button */}
<View style={{backgroundColor: theme.color.buttonPrimary}}>
<Text style={{color: theme.color.white}}>Primary Button</Text>
</View>
{/* Secondary button */}
<View style={{backgroundColor: theme.color.buttonSecondary}}>
<Text style={{color: theme.color.textBody}}>Secondary Button</Text>
</View>
{/* Theme accent variants */}
<View style={{backgroundColor: theme.color.themeAccent}}>
<Text>Theme Accent</Text>
</View>
<View style={{backgroundColor: theme.color.themeAccentD1}}>
<Text>Darker Variant</Text>
</View>
<View style={{backgroundColor: theme.color.themeAccentL1}}>
<Text>Lighter Variant</Text>
</View>
</View>
);
};const MyComponent = () => {
try {
const theme = useCustomTheme();
// Use theme
} catch (error) {
if (
error.message === 'useCustomTheme must be used within a ThemeProvider'
) {
// Handle missing provider
return <Text>Theme not available</Text>;
}
throw error;
}
};const MyComponent = () => {
try {
const theme = useCustomTheme();
// Validate specific properties
if (!theme.color?.primaryColor) {
return <Text>Primary color not available</Text>;
}
return <View style={{backgroundColor: theme.color.primaryColor}} />;
} catch (error) {
// Handle validation errors
return <Text>Theme validation failed</Text>;
}
};import {useThemedStyles} from '../shared/hooks/use-themed-styles';The useThemedStyles hook creates themed styles with automatic memoization, ensuring optimal performance by preventing unnecessary re-renders.
createStyles: (theme: CustomTheme) => T- Function that creates styles using theme data
T: Memoized styles object
import {useThemedStyles} from '../shared/hooks/use-themed-styles';
const MyComponent = () => {
const styles = useThemedStyles(theme => ({
container: {
backgroundColor: theme.color.bgColor,
padding: theme.spacing.md,
borderRadius: theme.radius.button,
},
text: {
color: theme.color.textBody,
fontSize: theme.typography.fontSize.base,
fontWeight: theme.typography.fontWeight.regular,
lineHeight: theme.typography.lineHeight.base,
},
}));
return (
<View style={styles.container}>
<Text style={styles.text}>Themed Content</Text>
</View>
);
};const ComplexComponent = () => {
const styles = useThemedStyles(theme => ({
container: {
backgroundColor: theme.color.pageBackground,
padding: theme.spacing.base,
margin: theme.spacing.md,
},
header: {
backgroundColor: theme.color.headerBackground,
padding: theme.spacing.md,
borderBottomWidth: 1,
borderBottomColor: theme.color.dividerStokes,
},
headerText: {
color: theme.color.textHeading,
fontSize: theme.typography.fontSize.lg,
fontWeight: theme.typography.fontWeight.bold,
lineHeight: theme.typography.lineHeight.lg,
},
content: {
padding: theme.spacing.md,
},
bodyText: {
color: theme.color.textBody,
fontSize: theme.typography.fontSize.base,
fontWeight: theme.typography.fontWeight.regular,
lineHeight: theme.typography.lineHeight.base,
},
button: {
backgroundColor: theme.color.buttonPrimary,
padding: theme.spacing.sm,
borderRadius: theme.radius.button,
alignItems: 'center',
},
buttonText: {
color: theme.color.white,
fontSize: theme.typography.fontSize.md,
fontWeight: theme.typography.fontWeight.medium,
},
}));
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>Header</Text>
</View>
<View style={styles.content}>
<Text style={styles.bodyText}>Content goes here</Text>
<TouchableOpacity style={styles.button}>
<Text style={styles.buttonText}>Action</Text>
</TouchableOpacity>
</View>
</View>
);
};const ConditionalComponent = ({isActive, isError}) => {
const styles = useThemedStyles(theme => ({
container: {
backgroundColor: isError
? theme.color.errorBackground
: isActive
? theme.color.successBackground
: theme.color.bgColor,
padding: theme.spacing.md,
borderRadius: theme.radius.button,
},
text: {
color: isError
? theme.color.errorText
: isActive
? theme.color.successText
: theme.color.textBody,
fontSize: theme.typography.fontSize.base,
fontWeight: theme.typography.fontWeight.medium,
},
}));
return (
<View style={styles.container}>
<Text style={styles.text}>
{isError ? 'Error State' : isActive ? 'Active State' : 'Default State'}
</Text>
</View>
);
};import {Dimensions} from 'react-native';
const ResponsiveComponent = () => {
const {width} = Dimensions.get('window');
const styles = useThemedStyles(theme => ({
container: {
backgroundColor: theme.color.bgColor,
padding: width > 768 ? theme.spacing.lg : theme.spacing.md,
flexDirection: width > 768 ? 'row' : 'column',
},
text: {
color: theme.color.textBody,
fontSize:
width > 768
? theme.typography.fontSize.lg
: theme.typography.fontSize.base,
lineHeight:
width > 768
? theme.typography.lineHeight.lg
: theme.typography.lineHeight.base,
},
}));
return (
<View style={styles.container}>
<Text style={styles.text}>Responsive Content</Text>
</View>
);
};import React from 'react';
import {View, Text, TouchableOpacity} from 'react-native';
import {useCustomTheme} from '../shared/hooks/use-custom-theme';
import {useThemedStyles} from '../shared/hooks/use-themed-styles';
const ThemedComponent = ({title, onPress, variant = 'primary'}) => {
const theme = useCustomTheme();
const styles = useThemedStyles(theme => ({
container: {
backgroundColor: theme.color.bgColor,
padding: theme.spacing.md,
borderRadius: theme.radius.button,
borderWidth: 1,
borderColor: theme.color.dividerStokes,
},
title: {
color: theme.color.textHeading,
fontSize: theme.typography.fontSize.lg,
fontWeight: theme.typography.fontWeight.bold,
lineHeight: theme.typography.lineHeight.lg,
marginBottom: theme.spacing.sm,
},
button: {
backgroundColor:
variant === 'primary'
? theme.color.buttonPrimary
: theme.color.buttonSecondary,
padding: theme.spacing.sm,
borderRadius: theme.radius.button,
alignItems: 'center',
},
buttonText: {
color: variant === 'primary' ? theme.color.white : theme.color.textBody,
fontSize: theme.typography.fontSize.md,
fontWeight: theme.typography.fontWeight.medium,
},
}));
return (
<View style={styles.container}>
<Text style={styles.title}>{title}</Text>
<TouchableOpacity style={styles.button} onPress={onPress}>
<Text style={styles.buttonText}>Action</Text>
</TouchableOpacity>
</View>
);
};const ThemedForm = () => {
const theme = useCustomTheme();
const styles = useThemedStyles(theme => ({
form: {
backgroundColor: theme.color.pageBackground,
padding: theme.spacing.base,
},
input: {
backgroundColor: theme.color.white,
borderWidth: 1,
borderColor: theme.color.dividerStokes,
borderRadius: theme.radius.button,
padding: theme.spacing.sm,
marginBottom: theme.spacing.md,
fontSize: theme.typography.fontSize.base,
color: theme.color.textBody,
},
label: {
color: theme.color.textLabel,
fontSize: theme.typography.fontSize.sm,
fontWeight: theme.typography.fontWeight.medium,
marginBottom: theme.spacing.xs,
},
submitButton: {
backgroundColor: theme.color.buttonPrimary,
padding: theme.spacing.md,
borderRadius: theme.radius.button,
alignItems: 'center',
},
submitButtonText: {
color: theme.color.white,
fontSize: theme.typography.fontSize.md,
fontWeight: theme.typography.fontWeight.bold,
},
}));
return (
<View style={styles.form}>
<Text style={styles.label}>Email</Text>
<TextInput style={styles.input} placeholder="Enter email" />
<Text style={styles.label}>Password</Text>
<TextInput
style={styles.input}
placeholder="Enter password"
secureTextEntry
/>
<TouchableOpacity style={styles.submitButton}>
<Text style={styles.submitButtonText}>Submit</Text>
</TouchableOpacity>
</View>
);
};// โ This will throw an error
const MyComponent = () => {
const theme = useCustomTheme(); // Error: must be used within ThemeProvider
return <View />;
};
// โ
Wrap with ThemeProvider
const App = () => (
<ThemeProvider>
<MyComponent />
</ThemeProvider>
);// โ This might fail if theme is incomplete
const MyComponent = () => {
const theme = useCustomTheme();
return <View style={{backgroundColor: theme.color.primaryColor}} />;
};
// โ
Add validation
const MyComponent = () => {
const theme = useCustomTheme();
if (!theme.color?.primaryColor) {
return <View style={{backgroundColor: '#000'}} />;
}
return <View style={{backgroundColor: theme.color.primaryColor}} />;
};// โ This will cause unnecessary re-renders
const MyComponent = () => {
const styles = useThemedStyles(theme => ({
container: {
backgroundColor: theme.color.bgColor,
// This function is recreated on every render
},
}));
return <View style={styles.container} />;
};
// โ
Move function outside component or use useCallback
const createStyles = theme => ({
container: {
backgroundColor: theme.color.bgColor,
},
});
const MyComponent = () => {
const styles = useThemedStyles(createStyles);
return <View style={styles.container} />;
};// Enable theme debugging
const debugTheme = () => {
const theme = useCustomTheme();
console.log('๐จ Theme Debug:', {
colorKeys: Object.keys(theme.color),
typographyKeys: Object.keys(theme.typography),
spacingKeys: Object.keys(theme.spacing),
hasRadius: !!theme.radius,
hasLayout: !!theme.layout,
});
};
// Use in development
if (__DEV__) {
debugTheme();
}- Use
useThemedStylesfor complex style objects - Memoize style creation functions
- Avoid inline styles when possible
- Always validate theme properties before use
- Use TypeScript for better IntelliSense
- Handle missing theme properties gracefully
- Keep style functions simple and focused
- Use descriptive style names
- Group related styles together
- Provide fallback values for missing theme properties
- Handle theme loading states
- Log errors for debugging
- Custom Theme Hooks: Specialized hooks for specific use cases
- Theme Validation: Runtime theme validation
- Performance Monitoring: Theme usage analytics
- Advanced Memoization: More sophisticated caching strategies
This documentation covers the main theme hooks. For more specific use cases or advanced patterns, refer to the other theme documentation sections.