What You Will Build

A furniture e-commerce grid with a badged shopping cart, product cards featuring square image placeholders, pricing, and add-to-cart actions. This extends the standard e-commerce pattern with furniture-specific design: larger images, minimal text, and prominent pricing.

Why This Pattern Matters

Furniture and home decor apps emphasize visual browsing. The 2-column grid with square aspect ratios gives products room to breathe. This is the layout used by IKEA, Wayfair, and West Elm mobile apps.

Step 1: Product Grid with Badge

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FurnitureAppScreen() {
    var cartCount by remember { mutableIntStateOf(0) }
    val products = remember { listOf(
        Product("Modern Sofa", 899.99, "Minimalist design", Icons.Default.Chair),
        Product("Floor Lamp", 149.99, "Ambient lighting", Icons.Default.Lightbulb),
        Product("Coffee Table", 349.99, "Solid oak", Icons.Default.TableBar),
        Product("Bookshelf", 279.99, "5-tier storage", Icons.Default.Shelves),
        Product("Desk Chair", 459.99, "Ergonomic", Icons.Default.EventSeat),
        Product("Side Table", 129.99, "Compact design", Icons.Default.Weekend)
    ) }

    Scaffold(
        topBar = {
            TopAppBar(
                title = { Text("Furniture App") },
                actions = {
                    BadgedBox(badge = {
                        if (cartCount > 0) Badge { Text("$cartCount") }
                    }) {
                        IconButton(onClick = {}) {
                            Icon(Icons.Default.ShoppingCart, "Cart")
                        }
                    }
                }
            )
        }
    ) { padding ->
        LazyVerticalGrid(
            columns = GridCells.Fixed(2),
            modifier = Modifier.padding(padding).padding(8.dp),
            verticalArrangement = Arrangement.spacedBy(8.dp),
            horizontalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            items(products) { product ->
                FurnitureProductCard(product) { cartCount++ }
            }
        }
    }
}

Step 2: Product Card Component

@Composable
fun FurnitureProductCard(product: Product, onAddToCart: () -> Unit) {
    Card(Modifier.fillMaxWidth()) {
        Column(Modifier.padding(12.dp)) {
            Box(
                Modifier.fillMaxWidth()
                    .aspectRatio(1f)
                    .clip(RoundedCornerShape(8.dp))
                    .background(MaterialTheme.colorScheme.primaryContainer),
                contentAlignment = Alignment.Center
            ) {
                Icon(product.icon, null, modifier = Modifier.size(48.dp))
            }
            Spacer(Modifier.height(8.dp))
            Text(product.name, fontWeight = FontWeight.SemiBold,
                maxLines = 1, overflow = TextOverflow.Ellipsis)
            Text(product.desc, fontSize = 12.sp,
                color = MaterialTheme.colorScheme.onSurfaceVariant)
            Row(
                Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text("${'$'}${String.format("%.2f", product.price)}",
                    fontWeight = FontWeight.Bold,
                    color = MaterialTheme.colorScheme.primary)
                IconButton(onClick = onAddToCart) {
                    Icon(Icons.Default.AddShoppingCart, "Add")
                }
            }
        }
    }
}

Tips and Pitfalls

  • Pass lambda callbacks (onAddToCart) instead of mutating state inside the card. This keeps cards stateless and reusable.
  • remember { listOf(...) } prevents the product list from being recreated on every recomposition.
  • For real images: Replace the Box+Icon placeholder with AsyncImage from Coil, keeping the same aspectRatio(1f) modifier.
  • Badge auto-hides when placed inside the if-check. No need for AnimatedVisibility unless you want a transition.

Min SDK: 21 | Compose BOM: 2024.01.00+

Get New Tutorials by Email

No spam. Just clear, practical breakdowns you can apply right away.

Enjoy this tutorial?

Get new practical tech tutorials in your inbox.