Skip to content

Compose Multiplatform Responsive Design with Composive

Master Responsive Design in Compose Multiplatform

Building responsive Compose Multiplatform applications has never been easier. Composive provides everything you need to create adaptive UIs that look perfect on every screen size and platform.

The Challenge of Responsive Compose Multiplatform

Traditional Compose Multiplatform development requires extensive manual work for responsive design:

Before Composive

// Complex manual breakpoint management
@Composable
fun ResponsiveLayout() {
    val configuration = LocalConfiguration.current
    val windowSizeClass = WindowSizeClass.calculateFromSize(
        DpSize(configuration.screenWidthDp.dp, configuration.screenHeightDp.dp)
    )

    when {
        windowSizeClass.widthSizeClass == WindowWidthSizeClass.Compact -> {
            // Mobile layout - manual implementation
        }
        windowSizeClass.widthSizeClass == WindowWidthSizeClass.Medium -> {
            // Tablet layout - manual implementation  
        }
        else -> {
            // Desktop layout - manual implementation
        }
    }
}

With Composive

// Automatic responsive behavior
@Composable
fun ResponsiveLayout() {
    ComposiveTheme {
        val deviceConfig = rememberDeviceConfiguration()

        when (deviceConfig) {
            DeviceConfiguration.MOBILE_PORTRAIT -> MobileLayout()
            DeviceConfiguration.TABLET_LANDSCAPE -> TabletLayout()
            DeviceConfiguration.DESKTOP -> DesktopLayout()
        }
    }
}

Key Features for Compose Multiplatform Responsive Design

🎯 Automatic Breakpoint Detection

Composive handles all the complexity of responsive breakpoints:

@Composable
fun AdaptiveGrid() {
    val columns = rememberDeviceConfiguration().getRecommendedColumns()

    LazyVerticalGrid(
        columns = GridCells.Fixed(columns) // Automatically: 1-4 columns
    ) {
        items(data) { item ->
            ResponsiveCard(item)
        }
    }
}

Automatic Column Recommendations: - Mobile Portrait: 1 column - Mobile Landscape: 2 columns
- Tablet Portrait: 2 columns - Tablet Landscape: 3 columns - Desktop: 4 columns

📱 Responsive Component System

Every component in Composive automatically adapts:

@Composable
fun ResponsiveCard(data: ItemData) {
    Card(
        modifier = Modifier.fillMaxWidth(),
        elevation = CardDefaults.cardElevation(
            defaultElevation = AppTheme.dimensions.cardElevation // Responsive!
        )
    ) {
        Column(
            modifier = Modifier.padding(
                AppTheme.dimensions.cardPadding // Scales with screen size!
            )
        ) {
            Text(
                text = data.title,
                style = AppTheme.materialTypography.titleMedium, // Responsive typography!
                fontWeight = AppTheme.fontWeights.heading
            )
        }
    }
}

🎨 Responsive Typography Scaling

Text automatically scales based on screen size:

Screen Size Body Text Headlines Scaling Factor
Mobile 16sp 24sp 1.0x
Tablet 18sp 28sp 1.125x
Desktop 20sp 32sp 1.25x
Text(
    text = "Scales Automatically",
    style = AppTheme.materialTypography.headlineLarge,
    // Automatically: 24sp → 28sp → 32sp based on screen
)

Real-World Compose Multiplatform Responsive Examples

📧 Responsive Email Client

@Composable
fun EmailApp() {
    ComposiveTheme {
        val deviceConfig = rememberDeviceConfiguration()

        when {
            deviceConfig.isMobile() -> {
                // Stack navigation for mobile
                EmailStackNavigation()
            }
            deviceConfig.isTablet() -> {
                // Master-detail for tablet
                Row {
                    EmailList(modifier = Modifier.weight(1f))
                    EmailDetail(modifier = Modifier.weight(1.5f))
                }
            }
            else -> {
                // Three-pane for desktop
                Row {
                    FolderSidebar(modifier = Modifier.width(240.dp))
                    EmailList(modifier = Modifier.weight(1f))
                    EmailDetail(modifier = Modifier.weight(2f))
                }
            }
        }
    }
}

🛍️ Responsive E-commerce App

@Composable
fun ProductCatalog() {
    val deviceConfig = rememberDeviceConfiguration()
    val showFilters = !deviceConfig.isMobile()

    if (showFilters) {
        Row {
            FilterSidebar(modifier = Modifier.width(280.dp))
            ProductGrid(modifier = Modifier.weight(1f))
        }
    } else {
        Column {
            SearchBar()
            ProductGrid(modifier = Modifier.weight(1f))
        }
    }
}

@Composable
fun ProductGrid(modifier: Modifier = Modifier) {
    val columns = rememberDeviceConfiguration().getRecommendedColumns()

    LazyVerticalGrid(
        columns = GridCells.Fixed(columns),
        modifier = modifier,
        contentPadding = PaddingValues(AppTheme.dimensions.screenPaddingHorizontal),
        horizontalArrangement = Arrangement.spacedBy(AppTheme.dimensions.cardSpacing)
    ) {
        items(products) { product ->
            ProductCard(product)
        }
    }
}

📊 Responsive Dashboard

@Composable
fun DashboardScreen() {
    val deviceConfig = rememberDeviceConfiguration()

    LazyVerticalGrid(
        columns = GridCells.Fixed(deviceConfig.getRecommendedColumns()),
        contentPadding = PaddingValues(AppTheme.dimensions.screenPaddingHorizontal),
        verticalArrangement = Arrangement.spacedBy(AppTheme.dimensions.cardSpacing),
        horizontalArrangement = Arrangement.spacedBy(AppTheme.dimensions.cardSpacing)
    ) {
        // Widgets automatically adapt to available space
        item { MetricCard("Users", "10.2K", trend = "+12%") }
        item { MetricCard("Revenue", "$45.8K", trend = "+8%") }
        item { ChartCard("Growth", growthData) }
        item { 
            ActivityCard(
                activities,
                modifier = Modifier.then(
                    if (deviceConfig.isDesktop()) {
                        Modifier.width(AppTheme.dimensions.dialogMaxWidth)
                    } else Modifier
                )
            )
        }
    }
}

Advanced Responsive Patterns

Adaptive Navigation

@Composable
fun AdaptiveNavigation() {
    val deviceConfig = rememberDeviceConfiguration()

    when {
        deviceConfig.isMobile() -> {
            // Bottom navigation for mobile
            Scaffold(
                bottomBar = {
                    NavigationBar {
                        NavigationBarItem(/* ... */)
                    }
                }
            ) { /* content */ }
        }

        deviceConfig.isTablet() -> {
            // Navigation rail for tablet
            Row {
                NavigationRail { NavigationRailItem(/* ... */) }
                MainContent()
            }
        }

        else -> {
            // Navigation drawer for desktop
            PermanentNavigationDrawer(
                drawerContent = { NavigationDrawerContent() }
            ) { MainContent() }
        }
    }
}

Responsive Dialog Handling

@Composable
fun ResponsiveDialog(
    showDialog: Boolean,
    onDismiss: () -> Unit,
    content: @Composable () -> Unit
) {
    val deviceConfig = rememberDeviceConfiguration()

    if (showDialog) {
        when {
            deviceConfig.isMobile() -> {
                // Full-screen on mobile
                Dialog(onDismissRequest = onDismiss) {
                    Surface(modifier = Modifier.fillMaxSize()) {
                        content()
                    }
                }
            }

            else -> {
                // Centered dialog on larger screens
                AlertDialog(
                    onDismissRequest = onDismiss,
                    modifier = Modifier.width(AppTheme.dimensions.dialogMaxWidth),
                    text = { content() },
                    confirmButton = { /* buttons */ }
                )
            }
        }
    }
}

Testing Responsive Compose Multiplatform Apps

🔥 Hot Reload Testing on Desktop

The fastest way to test responsive behavior:

# Run your app on desktop
./gradlew desktopRunHot

# Then resize the window to test different breakpoints:
# < 600dp width  → Mobile Portrait
# 600-840dp     → Mobile Landscape / Tablet Portrait  
# 840-1200dp    → Tablet Landscape
# > 1200dp      → Desktop

Debug Device Configuration

@Composable
fun DeviceDebugOverlay() {
    val deviceConfig = rememberDeviceConfiguration()

    if (BuildConfig.DEBUG) {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .padding(AppTheme.dimensions.space2),
            contentAlignment = Alignment.TopEnd
        ) {
            Card {
                Column(
                    modifier = Modifier.padding(AppTheme.dimensions.space2)
                ) {
                    Text("Config: $deviceConfig")
                    Text("Columns: ${deviceConfig.getRecommendedColumns()}")
                    Text("Mobile: ${deviceConfig.isMobile()}")
                    Text("Tablet: ${deviceConfig.isTablet()}")
                    Text("Desktop: ${deviceConfig.isDesktop()}")
                }
            }
        }
    }
}

Performance Benefits

Optimized Recomposition

Composive minimizes recomposition by caching device configuration:

@Composable
fun OptimizedResponsiveLayout() {
    // Device configuration is cached and only updates on actual changes
    val deviceConfig = rememberDeviceConfiguration()

    // This will only recompose when device configuration actually changes
    when (deviceConfig) {
        DeviceConfiguration.MOBILE_PORTRAIT -> MobileLayout()
        DeviceConfiguration.DESKTOP -> DesktopLayout()
    }
}

Smart Resource Loading

@Composable
fun ResponsiveImage(imageData: ImageData) {
    val deviceConfig = rememberDeviceConfiguration()

    // Load appropriate image size based on screen
    val imageUrl = when {
        deviceConfig.isMobile() -> imageData.thumbnailUrl
        deviceConfig.isTablet() -> imageData.mediumUrl
        else -> imageData.fullSizeUrl
    }

    AsyncImage(
        model = imageUrl,
        modifier = Modifier.size(AppTheme.dimensions.imageMedium)
    )
}

Getting Started with Responsive Compose Multiplatform

Installation via Maven Central

Add the following to your build.gradle.kts:

dependencies {
    implementation("io.github.gursimarsingh12:composive-responsive-adaptive:1.0.0")
}

Basic Setup

@Composable
fun App() {
    ComposiveTheme {
        // Your responsive app starts here!
        ResponsiveMainScreen()
    }
}

Next Steps

  1. Complete Installation Guide →
  2. Step-by-Step Tutorial →
  3. Real-World Examples →
  4. API Reference →

Why Choose Composive for Responsive Compose Multiplatform?

Zero Configuration - Works out of the box
Automatic Breakpoints - No manual calculations
Platform-Aware - Material 3 + Cupertino themes
Performance Optimized - Minimal recomposition
Developer Friendly - Familiar Compose APIs
Hot Reload Testing - Instant feedback on desktop

Start Building Responsive Apps →


Transform your Compose Multiplatform apps with effortless responsive design. 🚀