Skip to main content

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:

  1. Hero Section: Images, primary info, main CTA
  2. Content Sections: Organized information blocks
  3. Actions: Secondary actions and sharing
  4. 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.