Widget-Based Design

← Back to skills

> "Miniature applications. Small, highly functional blocks of UI designed to be rearranged."

Category: Frontend & UI/UX
Repo: antigravity-awesome-skills
Path: skills/design-it/widget-based-design/SKILL.md
Updated: 6/22/2026, 9:05:36 AM

AI Summary

> "Miniature applications. Small, highly functional blocks of UI designed to be rearranged.". It is useful for React and Next.js, CSS and design systems, UI components, accessibility, and frontend polish. Source: antigravity-awesome-skills (skills/design-it/widget-based-design/SKILL.md).

Widget-Based Design

"Miniature applications. Small, highly functional blocks of UI designed to be rearranged."

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. Strict Aspect Ratios: Widgets usually follow strict sizes (1x1 square, 2x1 rectangle, 2x2 large square).
  2. Glanceability: Widgets show the most important piece of data instantly. Deep interaction usually requires opening the full app.
  3. Corner Radius Match: The inner content's border radius should perfectly nest within the widget's outer border radius.

Visual DNA

  • Colors: Widgets often use bright, solid color backgrounds or full-bleed photos to differentiate themselves.
  • Typography: Large, bold numbers (like a clock or weather temp) paired with tiny sub-labels.
  • Layout: Similar to Bento UI, but specifically focused on functional app-lets rather than just content layout.

Web Implementation

  • CSS Example:
.widget-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  grid-auto-rows: 160px; /* Force squares */
  gap: 16px;
  padding: 32px;
}

.widget {
  background-color: #ffffff;
  border-radius: 24px; /* Classic iOS widget radius */
  box-shadow: 0 8px 24px rgba(0,0,0,0.08);
  padding: 16px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  overflow: hidden;
  position: relative;
}

/* Specific Sizes */
.widget-small { grid-column: span 1; grid-row: span 1; }
.widget-medium { grid-column: span 2; grid-row: span 1; }
.widget-large { grid-column: span 2; grid-row: span 2; }

/* Weather Widget Example */
.widget.weather {
  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
  color: white;
}
.weather-temp { font-size: 3rem; font-weight: 300; }
.weather-icon { position: absolute; top: 16px; right: 16px; font-size: 2rem; }

App Implementation

SwiftUI

struct WidgetDesignView: View {
    let columns = [GridItem(.flexible(), spacing: 16), GridItem(.flexible(), spacing: 16)]
    
    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns, spacing: 16) {
                // 2x1 Widget
                WeatherWidget()
                    .frame(height: 160) // Base unit height
                
                // 1x1 Widget
                FitnessWidget()
                    .frame(height: 160)
                
                // 1x1 Widget
                MusicWidget()
                    .frame(height: 160)
            }
            .padding(24)
        }
        .background(Color(white: 0.95))
    }
}

struct WeatherWidget: View {
    var body: some View {
        ZStack(alignment: .topTrailing) {
            LinearGradient(colors: [Color(hex: "4facfe"), Color(hex: "00f2fe")], startPoint: .topLeading, endPoint: .bottomTrailing)
            
            Image(systemName: "cloud.sun.fill")
                .foregroundColor(.white)
                .font(.system(size: 40))
                .padding()
            
            VStack(alignment: .leading) {
                Spacer()
                Text("72°")
                    .font(.system(size: 48, weight: .thin))
                    .foregroundColor(.white)
                Text("San Francisco")
                    .font(.subheadline)
                    .foregroundColor(.white.opacity(0.8))
            }
            .frame(maxWidth: .infinity, alignment: .leading)
            .padding()
        }
        .cornerRadius(24) // Classic iOS widget radius
        .shadow(color: .black.opacity(0.1), radius: 10, y: 5)
    }
}
  • SwiftUI is perfect for this. The LazyVGrid handles the layout, and cornerRadius(24) matches Apple's default widget styling perfectly.
  • Use ZStack as the root of the widget to easily overlay content on top of complex gradients or images.

Flutter

class WidgetDesignScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFFF2F2F2),
      body: GridView.count(
        crossAxisCount: 2, // 2 columns for a typical phone
        padding: const EdgeInsets.all(24),
        mainAxisSpacing: 16,
        crossAxisSpacing: 16,
        childAspectRatio: 1.0, // 1x1 squares
        children: [
          // Note: Flutter GridView doesn't easily span rows/cols out of the box.
          // flutter_staggered_grid_view is highly recommended for real widget layouts.
          _buildWeatherWidget(),
          _buildFitnessWidget(),
          _buildMusicWidget(),
        ],
      ),
    );
  }

  Widget _buildWeatherWidget() {
    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(24),
        gradient: const LinearGradient(colors: [Color(0xFF4FACFE), Color(0xFF00F2FE)]),
        boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 5))],
      ),
      padding: const EdgeInsets.all(16),
      child: Stack(
        children: [
          const Align(
            alignment: Alignment.topRight,
            child: Icon(Icons.cloud, color: Colors.white, size: 40),
          ),
          Align(
            alignment: Alignment.bottomLeft,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Text('72°', style: TextStyle(color: Colors.white, fontSize: 48, fontWeight: FontWeight.w300)),
                Text('San Francisco', style: TextStyle(color: Colors.white.withOpacity(0.8), fontSize: 14)),
              ],
            ),
          )
        ],
      ),
    );
  }
}
  • A Stack inside a Container with BorderRadius.circular(24) is the blueprint for every widget.
  • Standard GridView is too rigid for mixed 2x1 and 1x1 widgets. Use the flutter_staggered_grid_view package for production apps.

React Native

const WidgetDesignScreen = () => {
  return (
    <ScrollView style={{ flex: 1, backgroundColor: '#F2F2F2' }} contentContainerStyle={{ padding: 24 }}>
      <View style={{ flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', gap: 16 }}>
        
        {/* 2x1 Widget (Full width minus padding) */}
        <View style={[styles.widget, { width: '100%' }]}>
          <LinearGradient colors={['#4facfe', '#00f2fe']} style={styles.widgetBg} />
          <Text style={styles.temp}>72°</Text>
          <Text style={styles.sub}>San Francisco</Text>
        </View>

        {/* 1x1 Widgets (Half width minus half gap) */}
        <View style={[styles.widget, { width: '47%' }]}><Text>Fitness</Text></View>
        <View style={[styles.widget, { width: '47%' }]}><Text>Music</Text></View>

      </View>
    </ScrollView>
  );
};

const styles = StyleSheet.create({
  widget: {
    height: 160, // Fixed height forces square/rectangular aspect ratios
    borderRadius: 24,
    backgroundColor: '#FFF',
    padding: 16,
    justifyContent: 'flex-end',
    shadowColor: '#000', shadowOffset: { width: 0, height: 5 }, shadowOpacity: 0.1, shadowRadius: 10, elevation: 5,
    overflow: 'hidden'
  },
  widgetBg: {
    ...StyleSheet.absoluteFillObject,
    borderRadius: 24,
  },
  temp: { fontSize: 48, fontWeight: '300', color: '#FFF' },
  sub: { fontSize: 14, color: 'rgba(255,255,255,0.8)' }
});
  • In React Native, flexWrap: 'wrap' combined with percentage widths (e.g., 47% for 2 columns with a gap) is the cleanest way to build a responsive widget layout.
  • If using LinearGradient from expo-linear-gradient or react-native-linear-gradient, apply StyleSheet.absoluteFillObject so it sits behind the text.

Jetpack Compose

@Composable
fun WidgetDesignScreen() {
    LazyVerticalGrid(
        columns = GridCells.Fixed(2),
        modifier = Modifier.fillMaxSize().background(Color(0xFFF2F2F2)).padding(24.dp),
        horizontalArrangement = Arrangement.spacedBy(16.dp),
        verticalArrangement = Arrangement.spacedBy(16.dp)
    ) {
        // 2x1 Widget (Spans both columns)
        item(span = { GridItemSpan(2) }) {
            WeatherWidget(Modifier.height(160.dp))
        }
        // 1x1 Widgets
        item { Box(Modifier.height(160.dp).background(Color.White, RoundedCornerShape(24.dp))) }
        item { Box(Modifier.height(160.dp).background(Color.White, RoundedCornerShape(24.dp))) }
    }
}

@Composable
fun WeatherWidget(modifier: Modifier = Modifier) {
    Box(
        modifier = modifier
            .fillMaxWidth()
            .shadow(10.dp, RoundedCornerShape(24.dp))
            .background(Brush.linearGradient(listOf(Color(0xFF4FACFE), Color(0xFF00F2FE))), RoundedCornerShape(24.dp))
            .padding(16.dp)
    ) {
        // Icon
        Icon(Icons.Filled.Cloud, contentDescription = null, tint = Color.White, modifier = Modifier.align(Alignment.TopEnd).size(40.dp))
        
        // Data
        Column(modifier = Modifier.align(Alignment.BottomStart)) {
            Text("72°", fontSize = 48.sp, fontWeight = FontWeight.Light, color = Color.White)
            Text("San Francisco", fontSize = 14.sp, color = Color.White.copy(alpha = 0.8f))
        }
    }
}
  • LazyVerticalGrid with GridCells.Fixed(2) and GridItemSpan perfectly recreate iOS widget grids.
  • RoundedCornerShape(24.dp) is essential to sell the look.

Do's and Don'ts

  • DO: Use full-bleed background colors to make different widgets stand out.
  • DON'T: Put complex forms or scrollable lists inside a 1x1 widget.

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.

Related skills