--- name: tile-design description: Web and App implementation guide for Tile Design. Trigger when user wants Microsoft Metro style, sharp square information units, and horizontal scrolling grids. date_added: "2026-06-17" risk: safe source: self source_type: self --- # Tile Design (Metro UI) > "Authentically digital. Clean, sharp squares relying purely on typography and flat color." ## When to Use Use this sub-style when the user's request matches the aesthetic described above. This is a child reference of the `design-it` skill and is not meant to be triggered directly. ## Core Principles 1. **Sharp Corners**: Absolutely no border-radius. Everything is a perfect square or sharp rectangle. 2. **Live Data**: Tiles flip, scroll, or fade internally to show live updates without the user interacting. 3. **Horizontal Panning**: The grid often expands infinitely to the right, encouraging horizontal scrolling. ## Visual DNA - **Colors**: High saturation, flat colors. A dark background (pure black) with bright cyan, magenta, orange, and green tiles. - **Typography**: Extremely clean, light sans-serifs (like `Segoe UI Light`). Text is almost always pure white. - **Icons**: Simple, wireframe, monochromatic glyphs placed centrally or in the corner. ## Web Implementation - **CSS Example**: ```css body { background-color: #111; color: #fff; font-family: 'Segoe UI', sans-serif; overflow-x: auto; /* Horizontal scroll */ } .tile-group { display: grid; grid-template-columns: repeat(4, 150px); grid-auto-rows: 150px; gap: 8px; padding: 40px; } .tile { background-color: #0078D7; /* Classic Windows Blue */ padding: 12px; display: flex; flex-direction: column; justify-content: space-between; cursor: pointer; /* The "tilt" click effect */ transition: transform 0.1s; transform-origin: center; } .tile:active { transform: scale(0.95); } .tile-wide { grid-column: span 2; } .tile-large { grid-column: span 2; grid-row: span 2; } /* Live Tile Animation */ .tile-live-content { animation: slideUp 5s infinite; } @keyframes slideUp { 0%, 45% { transform: translateY(0); } 50%, 95% { transform: translateY(-100%); } /* Slides up to reveal next item */ 100% { transform: translateY(0); } } ``` ## App Implementation ### SwiftUI ```swift struct TileDesignView: View { let rows = [GridItem(.fixed(150), spacing: 8), GridItem(.fixed(150), spacing: 8)] var body: some View { ScrollView(.horizontal, showsIndicators: false) { LazyHGrid(rows: rows, spacing: 8) { TileView(title: "Mail", color: Color(hex: "0078D7"), icon: "envelope") TileView(title: "Photos", color: Color(hex: "00CC6A"), icon: "photo", isLarge: true) TileView(title: "Weather", color: Color(hex: "2D7D9A"), icon: "cloud.sun") TileView(title: "Calendar", color: Color(hex: "D13438"), icon: "calendar") } .padding(40) } .background(Color(hex: "111111").ignoresSafeArea()) } } struct TileView: View { let title: String let color: Color let icon: String var isLarge: Bool = false @State private var isPressed = false var body: some View { VStack(alignment: .leading) { Image(systemName: icon) .font(.system(size: 32, weight: .light)) .foregroundColor(.white) Spacer() Text(title) .font(.custom("Segoe UI", size: 16)) .foregroundColor(.white) } .padding(16) // Sharp corners are mandatory .frame(width: isLarge ? 308 : 150, height: isLarge ? 308 : 150, alignment: .leading) .background(color) .scaleEffect(isPressed ? 0.95 : 1.0) .animation(.spring(response: 0.2, dampingFraction: 0.5), value: isPressed) .onLongPressGesture(minimumDuration: .infinity, maximumDistance: .infinity, pressing: { pressing in isPressed = pressing }, perform: {}) } } ``` - A `LazyHGrid` inside a horizontal `ScrollView` perfectly replicates the Windows Phone / Windows 8 start screen. - Absolutely NO corner radius. - The `isPressed` state triggering a `.scaleEffect(0.95)` replicates the physical "tilt" interaction of Metro tiles. ### Flutter ```dart class TileDesignScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFF111111), body: SingleChildScrollView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.all(40), child: SizedBox( height: 308, // Two rows of 150px + 8px spacing child: Wrap( direction: Axis.vertical, spacing: 8, runSpacing: 8, children: [ _buildTile('Mail', const Color(0xFF0078D7), Icons.mail_outline), _buildTile('Weather', const Color(0xFF2D7D9A), Icons.cloud_outlined), _buildTile('Photos', const Color(0xFF00CC6A), Icons.photo_outlined, isLarge: true), _buildTile('Calendar', const Color(0xFFD13438), Icons.calendar_today), ], ), ), ), ); } Widget _buildTile(String title, Color color, IconData icon, {bool isLarge = false}) { return StatefulBuilder( builder: (context, setState) { bool isPressed = false; return GestureDetector( onTapDown: (_) => setState(() => isPressed = true), onTapUp: (_) => setState(() => isPressed = false), onTapCancel: () => setState(() => isPressed = false), child: AnimatedScale( scale: isPressed ? 0.95 : 1.0, duration: const Duration(milliseconds: 100), child: Container( width: isLarge ? 308 : 150, height: isLarge ? 308 : 150, color: color, // Sharp corners padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Icon(icon, color: Colors.white, size: 32), Text(title, style: const TextStyle(color: Colors.white, fontFamily: 'Segoe UI', fontSize: 16)), ], ), ), ), ); } ); } } ``` - `Wrap` with `direction: Axis.vertical` inside a horizontally scrolling `SizedBox` is the easiest way to build a Metro grid that flows left-to-right. - Wrap tiles in `GestureDetector` and `AnimatedScale` to handle the press animation. ### React Native ```jsx const TileDesignScreen = () => { return ( ); }; const Tile = ({ title, color, isLarge }) => { const scale = useRef(new Animated.Value(1)).current; const handlePressIn = () => Animated.spring(scale, { toValue: 0.95, useNativeDriver: true }).start(); const handlePressOut = () => Animated.spring(scale, { toValue: 1, useNativeDriver: true }).start(); return ( {title} ); }; ``` - Use a `` combined with a child `` that has a fixed `height` and `flexWrap: 'wrap', flexDirection: 'column'`. This forces children to form columns and flow horizontally. - Use `Animated.View` and `TouchableWithoutFeedback` to create the scale animation. ### Jetpack Compose ```kotlin @Composable fun TileDesignScreen() { LazyHorizontalGrid( rows = GridCells.Fixed(2), modifier = Modifier.fillMaxSize().background(Color(0xFF111111)), contentPadding = PaddingValues(40.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { item(span = { GridItemSpan(1) }) { Tile("Mail", Color(0xFF0078D7)) } // Note: LazyHorizontalGrid doesn't easily support spanning multiple rows (2x2 tiles). // For a true Metro layout, you often have to build a custom Layout or use staggered grids. item(span = { GridItemSpan(2) }) { Tile("Photos Wide", Color(0xFF00CC6A)) } item(span = { GridItemSpan(1) }) { Tile("Weather", Color(0xFF2D7D9A)) } } } @Composable fun Tile(title: String, color: Color) { var isPressed by remember { mutableStateOf(false) } val scale by animateFloatAsState(if (isPressed) 0.95f else 1.0f) Box( modifier = Modifier .size(150.dp) // Or wide/large based on params .scale(scale) .background(color) // Sharp corners! No RoundedCornerShape .pointerInput(Unit) { detectTapGestures( onPress = { isPressed = true tryAwaitRelease() isPressed = false } ) } .padding(16.dp) ) { // Icon Box(modifier = Modifier.size(32.dp).background(Color.White.copy(alpha = 0.5f)).align(Alignment.TopStart)) // Text Text( text = title, color = Color.White, fontFamily = FontFamily.SansSerif, modifier = Modifier.align(Alignment.BottomStart) ) } } ``` - `LazyHorizontalGrid` is the right tool, though building true 2x2 "Large" tiles requires custom layout math in Compose if mixing with 1x1 tiles. - `Modifier.scale()` paired with `pointerInput` `detectTapGestures` handles the Metro interaction. ## Do's and Don'ts - **DO**: Place the tile label text strictly in the bottom-left corner of the tile. - **DON'T**: Add drop shadows or gradients to the tiles. ## Limitations - This is a styling reference and does not replace environment-specific validation, accessibility testing, or expert review. - Ensure appropriate contrast ratios and responsive behaviors are verified separately.