Mobile UX Strategy
Platform-specific design patterns for iOS and Android applications
Mobile devices are the primary way parents discover activities and providers manage their Growth Platform. Our mobile guidelines ensure native, platform-appropriate experiences while maintaining Juniro's brand consistency.
๐ฑ Platform Philosophyโ
iOS Design Principlesโ
- Clarity: Clean typography, precise icons, appropriate spacing
- Deference: Content is king, UI elements support content
- Depth: Visual layers and motion provide vitality
Android Design Principlesโ
- Material Design: Google's design language for consistency
- Bold & Intentional: Purposeful color and typography
- Motion Provides Meaning: Animations guide user attention
Juniro's Mobile Strategyโ
- Native Feel: Platform-appropriate patterns and interactions
- Brand Consistency: Maintain Juniro's visual identity
- Performance First: Optimized for speed and responsiveness
- Accessibility: Inclusive design for all users
๐จ Visual Designโ
Typography Scale (Mobile)โ
/* Mobile-optimized typography */
--juniro-mobile-text-xs: 11px; /* Small labels, captions */
--juniro-mobile-text-sm: 13px; /* Secondary text */
--juniro-mobile-text-base: 16px; /* Body text (iOS/Android standard) */
--juniro-mobile-text-lg: 18px; /* Large body text */
--juniro-mobile-text-xl: 20px; /* Small headings */
--juniro-mobile-text-2xl: 24px; /* Section headings */
--juniro-mobile-text-3xl: 28px; /* Page headings */
--juniro-mobile-text-4xl: 34px; /* Large headings */
Touch Targetsโ
/* Minimum touch target sizes */
--juniro-touch-min: 44px; /* iOS minimum (44pt) */
--juniro-touch-android: 48px; /* Android minimum (48dp) */
--juniro-touch-comfortable: 56px; /* Comfortable for all users */
Spacing (Mobile)โ
/* Mobile-specific spacing */
--juniro-mobile-space-xs: 4px; /* Tight spacing */
--juniro-mobile-space-sm: 8px; /* Small gaps */
--juniro-mobile-space-md: 16px; /* Standard spacing */
--juniro-mobile-space-lg: 24px; /* Section spacing */
--juniro-mobile-space-xl: 32px; /* Large sections */
--juniro-mobile-space-2xl: 48px; /* Major sections */
/* Platform-specific safe areas */
--juniro-safe-top: env(safe-area-inset-top);
--juniro-safe-bottom: env(safe-area-inset-bottom);
--juniro-safe-left: env(safe-area-inset-left);
--juniro-safe-right: env(safe-area-inset-right);
๐งญ Navigation Patternsโ
Tab Navigationโ
Primary navigation pattern for both platforms.
iOS Implementation:
// iOS-style tab bar
<TabNavigator
appearance="iOS"
position="bottom"
safeArea={true}
>
<Tab
icon={<SearchIcon />}
label="Discover"
badge={newActivitiesCount}
/>
<Tab
icon={<BookmarksIcon />}
label="Saved"
/>
<Tab
icon={<CalendarIcon />}
label="Bookings"
badge={upcomingCount}
/>
<Tab
icon={<ProfileIcon />}
label="Profile"
/>
</TabNavigator>
Android Implementation:
// Material Design tab bar
<TabNavigator
appearance="Material"
position="bottom"
elevation={8}
>
<Tab
icon={<SearchIcon />}
label="Discover"
rippleEffect={true}
/>
<Tab
icon={<BookmarksIcon />}
label="Saved"
/>
<Tab
icon={<CalendarIcon />}
label="Bookings"
/>
<Tab
icon={<ProfileIcon />}
label="Profile"
/>
</TabNavigator>
Stack Navigationโ
Secondary navigation for detailed views.
Features:
- Platform-appropriate header styling
- Back navigation (swipe on iOS, arrow on Android)
- Title and action button support
- Search integration
// Cross-platform stack navigator
<StackNavigator>
<Screen
name="ActivityDetails"
options={{
title: "Activity Details",
headerRight: <ShareButton />,
headerStyle: {
backgroundColor: Platform.select({
ios: 'rgba(255,255,255,0.95)',
android: '#ffffff'
})
}
}}
/>
</StackNavigator>
๐ Screen Patternsโ
List Screensโ
Activity discovery, booking history, provider listings.
Design Principles:
- Scannable content hierarchy
- Clear action buttons
- Loading and empty states
- Pull-to-refresh support
// Activity list screen
<FlatList
data={activities}
renderItem={({ item }) => (
<ActivityCard
activity={item}
onPress={() => navigateToDetails(item.id)}
onBookmark={() => toggleBookmark(item.id)}
/>
)}
ItemSeparatorComponent={<Divider />}
refreshControl={
<RefreshControl
refreshing={isRefreshing}
onRefresh={handleRefresh}
tintColor="#0ea5e9"
/>
}
ListEmptyComponent={<EmptyState />}
/>
Detail Screensโ
Activity details, provider profiles, booking information.
Layout Structure:
- Hero Section: Images, primary info, main CTA
- Content Sections: Organized information blocks
- Actions: Secondary actions and sharing
- Related Content: Recommendations and similar items
// Activity detail screen
<ScrollView>
<HeroSection>
<ImageGallery images={activity.images} />
<PrimaryInfo>
<Title>{activity.name}</Title>
<Provider>{activity.provider}</Provider>
<Rating value={activity.rating} count={activity.reviewCount} />
</PrimaryInfo>
<BookingButton onPress={handleBooking} />
</HeroSection>
<ContentSection title="About">
<Description>{activity.description}</Description>
</ContentSection>
<ContentSection title="Schedule & Pricing">
<ScheduleCard schedule={activity.schedule} />
<PricingCard pricing={activity.pricing} />
</ContentSection>
</ScrollView>
Form Screensโ
User registration, booking forms, provider setup.
Best Practices:
- Single column layout
- Logical field grouping
- Inline validation
- Progress indicators for multi-step forms
- Keyboard-appropriate input types
// Provider registration form
<KeyboardAvoidingView>
<ScrollView>
<ProgressIndicator currentStep={2} totalSteps={4} />
<FormSection title="Business Information">
<Input
label="Business Name"
value={businessName}
onChangeText={setBusinessName}
autoComplete="organization"
required
/>
<Input
label="Phone Number"
value={phone}
onChangeText={setPhone}
keyboardType="phone-pad"
autoComplete="tel"
required
/>
</FormSection>
<FormActions>
<Button variant="secondary" onPress={goBack}>
Back
</Button>
<Button variant="primary" onPress={handleNext}>
Continue
</Button>
</FormActions>
</ScrollView>
</KeyboardAvoidingView>
๐ฏ Touch Interactionsโ
Gesturesโ
Standard platform gestures plus Juniro-specific actions.
iOS Gestures:
- Swipe Back: Navigate to previous screen
- Pull to Refresh: Refresh content lists
- Long Press: Context menus and previews
- Swipe Actions: Quick actions on list items
Android Gestures:
- Back Button: System back navigation
- Pull to Refresh: Material Design refresh
- Long Press: Context actions
- Swipe to Dismiss: Remove items or notifications
Haptic Feedbackโ
Provide tactile feedback for important interactions.
// iOS Haptic Feedback
import { HapticFeedback } from 'react-native';
const handleBooking = () => {
HapticFeedback.trigger('medium'); // Success feedback
bookActivity();
};
const handleError = () => {
HapticFeedback.trigger('heavy'); // Error feedback
showErrorMessage();
};
// Android Vibration
import { Vibration } from 'react-native';
const handleSuccess = () => {
Vibration.vibrate(100); // Short success vibration
showSuccessMessage();
};
Animation Guidelinesโ
Smooth, purposeful animations that feel native.
iOS Animations:
// iOS-style spring animations
Animated.spring(slideValue, {
toValue: 0,
tension: 100,
friction: 8,
useNativeDriver: true
}).start();
Android Animations:
// Material Design motion
Animated.timing(fadeValue, {
toValue: 1,
duration: 300,
easing: Easing.bezier(0.4, 0.0, 0.2, 1), // Material motion curve
useNativeDriver: true
}).start();
๐ Component Adaptationsโ
Activity Cards (Mobile)โ
Optimized for smaller screens and touch interaction.
<ActivityCard>
<ImageContainer>
<ActivityImage source={activity.image} />
<BookmarkButton
isBookmarked={activity.isBookmarked}
onPress={toggleBookmark}
/>
</ImageContainer>
<ContentContainer>
<ActivityTitle>{activity.name}</ActivityTitle>
<ProviderInfo>
<ProviderName>{activity.provider}</ProviderName>
<VerificationBadge verified={activity.isVerified} />
</ProviderInfo>
<MetaInfo>
<Rating value={activity.rating} />
<AgeRange>{activity.ageRange}</AgeRange>
<Distance>{activity.distance}</Distance>
</MetaInfo>
<PriceInfo>
<Price>{activity.price}</Price>
<BookingButton onPress={handleBooking} />
</PriceInfo>
</ContentContainer>
</ActivityCard>
Search Interface (Mobile)โ
Optimized for mobile search patterns.
<SearchContainer>
<SearchInput
placeholder="What activity are you looking for?"
value={searchQuery}
onChangeText={setSearchQuery}
autoFocus={false}
clearButtonMode="while-editing" // iOS
returnKeyType="search"
onSubmitEditing={handleSearch}
/>
<FilterButton onPress={showFilters}>
<FilterIcon />
{activeFiltersCount > 0 && (
<FilterBadge>{activeFiltersCount}</FilterBadge>
)}
</FilterButton>
</SearchContainer>
<RecentSearches>
{recentSearches.map(search => (
<SearchChip
key={search}
onPress={() => setSearchQuery(search)}
>
{search}
</SearchChip>
))}
</RecentSearches>
๐ง Platform-Specific Featuresโ
iOS Featuresโ
// iOS-specific implementations
import {
ActionSheetIOS,
Alert,
SafeAreaView,
StatusBar
} from 'react-native';
// iOS action sheet
const showActionSheet = () => {
ActionSheetIOS.showActionSheetWithOptions({
options: ['Cancel', 'Share Activity', 'Report Issue'],
cancelButtonIndex: 0,
destructiveButtonIndex: 2,
}, (buttonIndex) => {
// Handle selection
});
};
// iOS alert
const showConfirmation = () => {
Alert.alert(
'Cancel Booking',
'Are you sure you want to cancel this booking?',
[
{ text: 'Keep Booking', style: 'cancel' },
{ text: 'Cancel', style: 'destructive', onPress: handleCancel }
]
);
};
Android Featuresโ
// Android-specific implementations
import {
ToastAndroid,
BackHandler,
PermissionsAndroid
} from 'react-native';
// Android toast
const showToast = (message) => {
ToastAndroid.show(message, ToastAndroid.SHORT);
};
// Android back button handling
useEffect(() => {
const backHandler = BackHandler.addEventListener(
'hardwareBackPress',
handleBackPress
);
return () => backHandler.remove();
}, []);
// Android permissions
const requestLocationPermission = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
);
return granted === PermissionsAndroid.RESULTS.GRANTED;
} catch (err) {
console.warn(err);
return false;
}
};
๐ Dark Mode Supportโ
Automatic Theme Detectionโ
import { useColorScheme } from 'react-native';
const App = () => {
const colorScheme = useColorScheme();
const theme = colorScheme === 'dark' ? darkTheme : lightTheme;
return (
<ThemeProvider theme={theme}>
<AppNavigator />
</ThemeProvider>
);
};
Dark Mode Color Paletteโ
const darkTheme = {
colors: {
background: '#000000',
surface: '#121212',
surfaceVariant: '#1e1e1e',
primary: '#66b3ff', // Lighter blue for dark backgrounds
text: '#ffffff',
textSecondary: '#a0a0a0',
border: '#333333',
}
};
const lightTheme = {
colors: {
background: '#ffffff',
surface: '#f8f9fa',
surfaceVariant: '#f1f3f4',
primary: '#0ea5e9', // Standard blue
text: '#000000',
textSecondary: '#6b7280',
border: '#e5e7eb',
}
};
๐ Responsive Designโ
Screen Size Adaptationsโ
import { Dimensions } from 'react-native';
const { width, height } = Dimensions.get('window');
// Responsive breakpoints
const isTablet = width >= 768;
const isLandscape = width > height;
// Adaptive layouts
const getColumns = () => {
if (isTablet) {
return isLandscape ? 3 : 2;
}
return 1;
};
// Responsive spacing
const getSpacing = (base) => {
return isTablet ? base * 1.5 : base;
};
Dynamic Type Supportโ
// iOS Dynamic Type support
import { PixelRatio, Platform } from 'react-native';
const getFontSize = (baseSize) => {
if (Platform.OS === 'ios') {
const scale = PixelRatio.getFontScale();
return baseSize * scale;
}
return baseSize;
};
// Android font scaling
const getScaledFont = (size) => {
const scale = PixelRatio.getFontScale();
return Math.round(size * scale);
};
๐งช Testing Guidelinesโ
Device Testingโ
iOS Testing Matrix:
- iPhone SE (small screen)
- iPhone 14 (standard)
- iPhone 14 Pro Max (large screen)
- iPad (tablet experience)
Android Testing Matrix:
- Small phone (5" - 5.5")
- Standard phone (5.5" - 6.5")
- Large phone (6.5"+)
- Tablet (7"+)
Accessibility Testingโ
- VoiceOver (iOS) navigation
- TalkBack (Android) navigation
- Switch Control testing
- Voice Control testing
- Dynamic Type scaling
- High contrast mode
Performance Testingโ
- Launch time optimization
- Scroll performance (60fps)
- Memory usage monitoring
- Battery impact assessment
- Network efficiency
These mobile guidelines will inform our React Native components when we build the mobile design system in our multi-repo architecture.