Styling & Theme
The most fundamental difference between React and Flutter UI work is this: there is no stylesheet. No CSS files, no className, no styled-components, no Tailwind utility classes. Styling in Flutter is expressed entirely through widget constructor properties. Color, typography, spacing, and decoration are all Dart objects nested inside the widget tree.
For app-wide design tokens — brand colours, text scales, button shapes — Flutter uses ThemeData, which you configure once at MaterialApp(theme: ...) and consume anywhere via Theme.of(context). This is the direct equivalent of a ThemeProvider wrapping your React app.
Side-by-side comparison
Section titled “Side-by-side comparison”// React — CSS-in-JS / styled-components style
// 1. Inline styles (like Flutter widget props)<p style={{ fontSize: 18, color: '#1a1a1a', fontWeight: 700 }}> Hello</p>
// 2. styled-components (design token from ThemeProvider)const Heading = styled.h1` font-size: ${({ theme }) => theme.fontSizes.xl}px; color: ${({ theme }) => theme.colors.primary}; font-weight: 700;`;
// 3. ThemeProvider wrapping the app<ThemeProvider theme={myTheme}> <App /></ThemeProvider>
// 4. Consuming the theme in a componentconst { theme } = useTheme();<div style={{ background: theme.colors.surface }}>...</div>// Flutter — widget properties + ThemeData
// 1. Inline TextStyle (equivalent to inline styles)Text( 'Hello', style: TextStyle( fontSize: 18, color: Color(0xFF1A1A1A), fontWeight: FontWeight.bold, ),)
// 2. BoxDecoration (background, border, radius, shadow)Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey[300]!), ), child: ...,)
// 3. ThemeData wrapping the app (in MaterialApp)MaterialApp( theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), textTheme: const TextTheme( headlineMedium: TextStyle(fontWeight: FontWeight.bold), ), ), home: const MyHome(),)
// 4. Consuming the theme anywherefinal theme = Theme.of(context);Container(color: theme.colorScheme.surface, ...)Runnable example
Section titled “Runnable example”import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF0468D7)),
useMaterial3: true,
textTheme: const TextTheme(
headlineSmall: TextStyle(fontWeight: FontWeight.bold, fontSize: 22),
bodyMedium: TextStyle(fontSize: 15, height: 1.6),
),
),
home: const StyleDemo(),
),
);
}
class StyleDemo extends StatelessWidget {
const StyleDemo({super.key});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final cs = theme.colorScheme;
return Scaffold(
backgroundColor: cs.surfaceContainerLow,
appBar: AppBar(
backgroundColor: cs.primary,
title: Text('Styling & Theme',
style: TextStyle(color: cs.onPrimary, fontWeight: FontWeight.bold)),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
spacing: 16,
children: [
// TextStyle from theme
Text('Headline from ThemeData',
style: theme.textTheme.headlineSmall),
Text('Body text with theme line-height',
style: theme.textTheme.bodyMedium),
// TextStyle override via copyWith
Text('Local color override',
style: theme.textTheme.bodyMedium!
.copyWith(color: cs.error, fontWeight: FontWeight.w600)),
// BoxDecoration card
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: cs.primaryContainer,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8,
children: [
Text('Primary container card',
style: TextStyle(color: cs.onPrimaryContainer,
fontWeight: FontWeight.bold, fontSize: 16)),
Text('Colours from ColorScheme.fromSeed',
style: TextStyle(color: cs.onPrimaryContainer)),
],
),
),
// BoxDecoration with gradient
Container(
height: 80,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [cs.primary, cs.tertiary],
),
borderRadius: BorderRadius.circular(12),
),
alignment: Alignment.center,
child: Text('Gradient via BoxDecoration',
style: TextStyle(color: cs.onPrimary,
fontWeight: FontWeight.bold)),
),
// Buttons inherit theme automatically
Row(
spacing: 8,
children: [
ElevatedButton(onPressed: () {}, child: const Text('Elevated')),
TextButton(onPressed: () {}, child: const Text('Text')),
OutlinedButton(onPressed: () {}, child: const Text('Outlined')),
],
),
],
),
),
);
}
}