Theme System
Theme System
Section titled “Theme System”Problem and Rationale
Section titled “Problem and Rationale”Zelta Chat requires consistent styling to:
- Maintain visual consistency across screens
- Support light and dark mode variations
- Provide accessible color contrasts
- Enable rapid UI development with utility classes
- Scale typography for different screen sizes
Why Tailwind CSS (TWRNC):
- Utility-first approach for rapid development
- Consistent spacing and sizing scales
- Easy responsive design
- No runtime style sheet generation
- TypeScript support via
twrncpackage
Design
Section titled “Design”Theme Architecture
Section titled “Theme Architecture”twConfig (tailwind.config.ts) ├─ Base Theme (Tailwind defaults) ├─ Extended Colors │ ├─ Radix UI Light Colors │ ├─ Radix UI Dark Colors │ ├─ Black Alpha variations │ └─ White Alpha variations ├─ Extended Typography │ ├─ Custom font sizes (xs, cxs, md) │ └─ Inter font family variants └─ PluginsColor System
Section titled “Color System”Color Categories:
-
UI Colors - Neutral interface colors
- gray1-12, mauve1-12, slate1-12
-
Nature Colors - Natural tones
- sage1-12, olive1-12, sand1-12
-
Primary Colors - Brand and interactive elements
- blue1-12, indigo1-12, violet1-12
-
Accent Colors - Alerts and highlights
- tomato1-12, red1-12, ruby1-12, crimson1-12
-
Success/Info Colors
- mint1-12, lime1-12, yellow1-12, amber1-12
-
Special Colors
- brown1-12, bronze1-12, gold1-12
-
Alpha Variations - Transparency support
- blackA1-12, whiteA1-12
Color Scale:
Each color has 12 steps:
1-3: Backgrounds and subtle elements4-6: Borders and separators7-9: Interactive states (hover, active)10-12: High contrast text and icons
Typography System
Section titled “Typography System”Font Family:
fontFamily: { 'inter-normal-20': ['Inter-400-20'], // Regular 400, optical size 20 'inter-420-20': ['Inter-420-20'], // Light Medium 420 'inter-medium-24': ['Inter-500-24'], // Medium 500, optical size 24 'inter-580-24': ['Inter-580-24'], // Semi Medium 580 'inter-semibold-20': ['Inter-600-20'], // Semi Bold 600}Font Sizes:
fontSize: { xs: '12px', // Extra small cxs: '13px', // Custom extra small md: '15px', // Medium (custom, larger than default)}Lifecycle and Data Flow
Section titled “Lifecycle and Data Flow”Style Application Flow
Section titled “Style Application Flow”Component Render ↓Import tailwind instance ↓Apply utility classes: tailwind('bg-blue-500 p-4') ↓TWRNC parses classes ↓Generate React Native style object ↓Apply to component style prop ↓Render with stylesTheme Configuration Loading
Section titled “Theme Configuration Loading”App Initialization ↓Load twConfig from tailwind.config.ts ↓Create tailwind instance with config ↓Export configured instance ↓Import in componentsImplementation Notes
Section titled “Implementation Notes”Tailwind Configuration
Section titled “Tailwind Configuration”Configuration File (src/theme/tailwind.config.ts):
const defaultTheme = require('tailwindcss/defaultTheme');const radixUILightColors = require('./colors/light');const radixUIDarkColors = require('./colors/dark');const blackA = require('./colors/blackA');const whiteA = require('./colors/whiteA');
const Zelta ChatAppColors = { ...blackA, ...whiteA, ...radixUILightColors, ...radixUIDarkColors,};
export const twConfig = { theme: { ...defaultTheme, extend: { colors: { ...Zelta ChatAppColors }, fontSize: { xs: '12px', cxs: '13px', md: '15px', }, fontFamily: { 'inter-normal-20': ['Inter-400-20'], 'inter-420-20': ['Inter-420-20'], 'inter-medium-24': ['Inter-500-24'], 'inter-580-24': ['Inter-580-24'], 'inter-semibold-20': ['Inter-600-20'], }, }, }, plugins: [],};Tailwind Instance Creation
Section titled “Tailwind Instance Creation”Instance Export (src/theme/tailwind.ts):
import { create } from 'twrnc';import { twConfig } from './tailwind.config';
const tailwind = create(twConfig);
export default tailwind;Usage in Components
Section titled “Usage in Components”Basic Styling:
import tailwind from '@/theme/tailwind';import { View, Text } from 'react-native';
export const MyComponent = () => { return ( <View style={tailwind('bg-gray-2 p-4 rounded-lg')}> <Text style={tailwind('text-gray-12 font-inter-medium-24 text-md')}> Hello World </Text> </View> );};Conditional Styling:
const MyComponent = ({ isActive }: { isActive: boolean }) => { return ( <View style={tailwind(` p-4 rounded-lg ${isActive ? 'bg-blue-9' : 'bg-gray-3'} `)}> <Text style={tailwind('text-gray-12')}>Status</Text> </View> );};Combining with React Native Styles:
import { StyleSheet } from 'react-native';
const MyComponent = () => { return ( <View style={[ tailwind('p-4'), styles.shadow, // Custom styles ]}> <Text>Content</Text> </View> );};
const styles = StyleSheet.create({ shadow: { shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3, },});Patterns and Anti-Patterns
Section titled “Patterns and Anti-Patterns”✅ Good Patterns:
// Use semantic color scales<View style={tailwind('bg-gray-2 border border-gray-6')}> <Text style={tailwind('text-gray-12')}>Content</Text></View>
// Use consistent spacing scale<View style={tailwind('p-4 mb-2 mt-6')}>
// Responsive font sizes<Text style={tailwind('text-md font-inter-medium-24')}>
// Alpha colors for overlays<View style={tailwind('bg-blackA-11 absolute inset-0')} />❌ Anti-Patterns:
// DON'T: Use arbitrary values (not in Tailwind config)<View style={{ backgroundColor: '#ff0000' }}> // ❌ Use color scale
// DON'T: Mix utility classes with inline styles unnecessarily<Text style={[tailwind('text-md'), { fontSize: 16 }]}> // ❌ Conflicting
// DON'T: Overuse nested ternariesstyle={tailwind(`${condition1 ? (condition2 ? 'a' : 'b') : 'c'}`)} // ❌ Hard to readPerformance Considerations
Section titled “Performance Considerations”Style Memoization
Section titled “Style Memoization”Memoize computed styles for frequently rendered components:
import { useMemo } from 'react';
const MyListItem = ({ isActive }: { isActive: boolean }) => { const containerStyle = useMemo( () => tailwind(`p-4 ${isActive ? 'bg-blue-3' : 'bg-gray-2'}`), [isActive] );
return <View style={containerStyle}>...</View>;};Avoid Dynamic Class Generation
Section titled “Avoid Dynamic Class Generation”// ❌ Bad: Generates new style object every render<View style={tailwind(`bg-gray-${Math.floor(opacity * 12)}`)}>
// ✅ Good: Use predefined classes<View style={tailwind(opacity > 0.5 ? 'bg-gray-9' : 'bg-gray-3')}>Testing Strategy
Section titled “Testing Strategy”Style Tests
Section titled “Style Tests”import tailwind from '@/theme/tailwind';
describe('Theme System', () => { it('should apply correct background color', () => { const style = tailwind('bg-blue-9'); expect(style.backgroundColor).toBeDefined(); });
it('should apply custom font family', () => { const style = tailwind('font-inter-medium-24'); expect(style.fontFamily).toContain('Inter-500-24'); });});Component Visual Tests
Section titled “Component Visual Tests”Use Storybook for visual regression testing:
export default { title: 'Components/MyComponent', component: MyComponent,};
export const Default = () => <MyComponent />;export const Active = () => <MyComponent isActive />;export const Disabled = () => <MyComponent disabled />;Extending This Concept
Section titled “Extending This Concept”Adding Custom Colors
Section titled “Adding Custom Colors”export const customColors = { brand: { primary: '#1e40af', secondary: '#3b82f6', },};
// Update tailwind.config.tsconst Zelta ChatAppColors = { ...blackA, ...whiteA, ...radixUILightColors, ...customColors,};Adding Dark Mode Support
Section titled “Adding Dark Mode Support”import { useColorScheme } from 'react-native';
const MyComponent = () => { const colorScheme = useColorScheme(); const isDark = colorScheme === 'dark';
return ( <View style={tailwind(` p-4 ${isDark ? 'bg-gray-12' : 'bg-gray-1'} `)}> <Text style={tailwind(isDark ? 'text-gray-1' : 'text-gray-12')}> Content </Text> </View> );};Creating Custom Utility Classes
Section titled “Creating Custom Utility Classes”// Extend Tailwind config with custom utilitiesexport const twConfig = { theme: { extend: { // ... existing config spacing: { '128': '32rem', }, borderRadius: { '4xl': '2rem', }, }, }, plugins: [ // Custom plugin for shadows ({ addUtilities }) => { addUtilities({ '.shadow-card': { shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 8, elevation: 3, }, }); }, ],};Further Reading
Section titled “Further Reading”- UI Components - Component styling examples
- Tailwind CSS Documentation
- TWRNC Documentation
- Radix Colors - Color system foundation