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:
Basic Setup¶
@Composable
fun App() {
ComposiveTheme {
// Your responsive app starts here!
ResponsiveMainScreen()
}
}
Next Steps¶
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. 🚀