Guides Material 3 theming best practices in Flutter using ThemeData as single source of truth for colors, typography, components, spacing, and light/dark modes. Use for creating, modifying, or reviewing themes.
npx claudepluginhub verygoodopensource/very_good_claude_code_marketplace --plugin vgv-ai-flutter-pluginThis skill is limited to using the following tools:
Material 3 theming best practices for Flutter applications using `ThemeData` as the single source of truth for colors, typography, component styles, and spacing.
Guides Material Design 3 (Material You) implementation for Android (Jetpack Compose), Flutter, and web apps with dynamic theming, colors, typography, layouts, and components.
Implements best practices for Flutter UI packages: Material-based custom components, ThemeExtension theming, consistent APIs, barrel exports, and widget tests. Use for 'create a ui package'.
Implements Material Design 3 UI with 30+ components, design tokens, seed-color theming, responsive scaffolds, navigation patterns, and compliance audits for web (@material/web), Flutter, Jetpack Compose.
Share bugs, ideas, or general feedback.
Material 3 theming best practices for Flutter applications using ThemeData as the single source of truth for colors, typography, component styles, and spacing.
Apply these standards to ALL theming work:
ThemeData as the single source of truth — never inline colors or text styles in widgetsTheme.of(context).colorScheme — never Colors.blue, Colors.red, or any hardcoded Color valuesTheme.of(context).textTheme — never inline TextStyle(...) in widget codeColorScheme for all color definitions — Material 3's structured color systemThemeData — define FilledButtonThemeData, InputDecorationTheme, etc. in the theme, not per-widgetThemeData so theme switching requires zero conditional logic in widgetsThemeData handle itEdgeInsets.only and EdgeInsets.symmetric — never EdgeInsets.fromLTRB (positional arguments are error-prone)Centralize all color definitions in a dedicated class:
abstract class AppColors {
static const primaryColor = Color(0xFF4F46E5);
static const secondaryColor = Color(0xFF9C27B0);
static const errorColor = Color(0xFFDC2626);
static const surfaceColor = Color(0xFFFAFAFA);
}
ColorScheme ConfigurationThe ColorScheme class includes 45 colors based on Material 3 specifications. Configure it within ThemeData:
ThemeData(
colorScheme: ColorScheme(
brightness: Brightness.light,
primary: AppColors.primaryColor,
secondary: AppColors.secondaryColor,
error: AppColors.errorColor,
surface: AppColors.surfaceColor,
onPrimary: Colors.white,
onSecondary: Colors.white,
onError: Colors.white,
onSurface: Colors.black,
),
)
For quick prototyping, use ColorScheme.fromSeed():
ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: AppColors.primaryColor,
),
)
class AppTheme {
static ThemeData get light => ThemeData(
colorScheme: ColorScheme(
brightness: Brightness.light,
primary: AppColors.primaryColor,
surface: AppColors.surfaceColor,
// ... remaining color roles
),
);
static ThemeData get dark => ThemeData(
colorScheme: ColorScheme(
brightness: Brightness.dark,
primary: AppColors.primaryColorDark,
surface: AppColors.surfaceColorDark,
// ... remaining color roles
),
);
}
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return ColoredBox(
color: colorScheme.surface,
child: Text(
'Hello',
style: TextStyle(color: colorScheme.onSurface),
),
);
}
Define an AppTextStyle class with a base style and named variants (displayLarge, headlineMedium, bodyLarge, etc.), then integrate them into ThemeData.textTheme. Access styles via Theme.of(context).textTheme.
See references/typography.md for font asset setup, the full AppTextStyle class, TextTheme integration, and widget access patterns.
Define component themes centrally in ThemeData (e.g., filledButtonTheme, inputDecorationTheme, appBarTheme) instead of styling individual widget instances. A complete AppTheme class assembles ColorScheme, TextTheme, and all component themes into a single ThemeData.
See references/components.md for FilledButton, InputDecoration, and AppBar theme examples, the complete theme assembly, and widget access patterns.
Define an AppSpacing class with a base unit (e.g., 16px) and named constants (xxs through xxlg). Use EdgeInsets.only or EdgeInsets.symmetric — never EdgeInsets.fromLTRB.
See references/spacing.md for the full AppSpacing class, usage examples, and EdgeInsets preferences.
AppColors with all color constantsAppTextStyle with all text style constantsAppSpacing with spacing scale based on a base unitAppTheme class with light and dark gettersColorScheme, TextTheme, and component themes in each ThemeDataAppTheme.light and AppTheme.dark to MaterialAppAppColorsColorScheme role (or create a theme extension for custom tokens)Theme.of(context).colorScheme.<role> in widgetsColorScheme instances for light and darkTextTheme and component themes (they adapt automatically via colorScheme)MaterialApp via theme and darkThemeBrightness in widget code — let ThemeData handle the switch| ThemeData Property | Purpose |
|---|---|
colorScheme | Material 3 color system (45 color roles) |
textTheme | Typography scale (display, headline, body…) |
filledButtonTheme | FilledButton default style |
inputDecorationTheme | TextField/TextFormField decoration defaults |
appBarTheme | AppBar default styling |
cardTheme | Card default styling |
dialogTheme | Dialog default styling |
| Material 3 Color Role | Typical Use |
|---|---|
primary | Key UI elements, FAB, active states |
onPrimary | Text/icons on primary color |
secondary | Less prominent UI elements |
surface | Card, sheet, dialog backgrounds |
onSurface | Text/icons on surface color |
error | Error indicators, destructive actions |
outline | Borders, dividers |