Skip to content

Composition over Configuration

React’s composition model — small components that accept children, higher-order components that wrap behavior, and render props — maps cleanly onto Flutter’s widget model. In Flutter you compose behavior by wrapping widgets: Padding(child: ...), GestureDetector(child: ...), Opacity(child: ...). There is no equivalent to CSS class inheritance or widget subclassing for visual customization. Everything is composition.

React
// React — children prop
function Card({ children, elevated }) {
return (
<div
style={{
padding: 16,
borderRadius: 12,
boxShadow: elevated ? '0 4px 12px rgba(0,0,0,0.1)' : 'none',
}}
>
{children}
</div>
);
}
// Usage
<Card elevated>
<h3>Hello</h3>
<p>Composed content</p>
</Card>
Flutter
// Flutter — wrapper widget with child
class AppCard extends StatelessWidget {
final Widget child;
final bool elevated;
const AppCard({super.key, required this.child, this.elevated = false});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: elevated
? [BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 12,
offset: const Offset(0, 4))]
: [],
),
child: child,
);
}
}
// Usage
AppCard(
elevated: true,
child: Column(
children: [
Text('Hello', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Text('Composed content'),
],
),
)
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.grey[100],
        body: Padding(
          padding: const EdgeInsets.all(24),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              AppCard(
                elevated: true,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: const [
                    Text('Getting Started', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
                    SizedBox(height: 4),
                    Text('Learn the basics of Flutter composition.', style: TextStyle(color: Colors.grey)),
                  ],
                ),
              ),
              const SizedBox(height: 16),
              AppCard(
                elevated: true,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: const [
                    Text('Widget Tree', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
                    SizedBox(height: 4),
                    Text('Everything is a widget — compose, not configure.', style: TextStyle(color: Colors.grey)),
                  ],
                ),
              ),
              const SizedBox(height: 16),
              AppCard(
                elevated: true,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: const [
                    Text('Declarative UI', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
                    SizedBox(height: 4),
                    Text('UI = f(state) — the same idea you know from React.', style: TextStyle(color: Colors.grey)),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class AppCard extends StatelessWidget {
  final Widget child;
  final bool elevated;
  const AppCard({super.key, required this.child, this.elevated = false});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(12),
        boxShadow: elevated
            ? [
                BoxShadow(
                  color: Colors.black.withOpacity(0.1),
                  blurRadius: 12,
                  offset: const Offset(0, 4),
                )
              ]
            : [],
      ),
      child: child,
    );
  }
}
What is the Flutter equivalent of React's children prop?
In Flutter, how do you add a tap handler to any widget?
React render props (passing a function that returns JSX) map to Flutter as:
Why does Flutter prefer composition over inheritance for visual customization?