# Flutter Theming

> How to customize your app's theme using Flutter's theming system

- Skill: `xuelongqy/flutter-theming` (Agent Skill)
- Install (CLI): `npx skillmds@latest add xuelongqy/flutter-theming`
- Raw SKILL.md: https://api.skillmd.com/api/skills/xuelongqy/flutter-theming/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: xuelongqy (https://skillmd.com/u/xuelongqy)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/xuelongqy/flutter-theming

---

## Goal
Updates and manages Flutter application styling by migrating legacy Material 2 implementations to Material 3, normalizing component themes, updating deprecated button classes, and adapting UI idioms for cross-platform consistency. Assumes a Flutter environment using Dart.

## Instructions

1. **Analyze Current Theme State**
   Review the existing Flutter codebase to identify legacy Material 2 components, deprecated button classes (`FlatButton`, `RaisedButton`, `OutlineButton`), and outdated theme properties (e.g., `accentColor`, `color` in `AppBarTheme`).
   **STOP AND ASK THE USER:** "What is the primary seed color for the new Material 3 ColorScheme, and which target platforms (iOS, Android, Windows, macOS, Linux, Web) should be prioritized for platform idioms?"

2. **Decision Logic: Component Migration**
   When encountering legacy widgets, use the following decision tree to determine the replacement:
   * IF `BottomNavigationBar` -> REPLACE WITH `NavigationBar` (uses `NavigationDestination`).
   * IF `Drawer` -> REPLACE WITH `NavigationDrawer` (uses `NavigationDrawerDestination`).
   * IF `ToggleButtons` -> REPLACE WITH `SegmentedButton` (uses `ButtonSegment` and `Set` for selection).
   * IF `FlatButton` -> REPLACE WITH `TextButton`.
   * IF `RaisedButton` -> REPLACE WITH `ElevatedButton` (or `FilledButton` for no elevation).
   * IF `OutlineButton` -> REPLACE WITH `OutlinedButton`.

3. **Implement App-Wide Material 3 Theme**
   Define the global `ThemeData` using `ColorScheme.fromSeed`. Ensure `useMaterial3` is implicitly or explicitly true. Remove all references to deprecated accent properties (`accentColor`, `accentColorBrightness`, `accentTextTheme`, `accentIconTheme`).

   ```dart
   MaterialApp(
     title: 'App Name',
     theme: ThemeData(
       useMaterial3: true,
       colorScheme: ColorScheme.fromSeed(
         seedColor: Colors.deepPurple,
         brightness: Brightness.light,
       ),
       // Use colorScheme.secondary instead of accentColor
     ),
     darkTheme: ThemeData(
       useMaterial3: true,
       colorScheme: ColorScheme.fromSeed(
         seedColor: Colors.deepPurple,
         brightness: Brightness.dark,
       ),
     ),
     home: const MyHomePage(),
   );
   ```

4. **Normalize Component Themes**
   Update all component theme definitions in `ThemeData` to use their `*ThemeData` equivalents. Do not use the base theme classes for configuration.
   * `cardTheme` -> `CardThemeData`
   * `dialogTheme` -> `DialogThemeData`
   * `tabBarTheme` -> `TabBarThemeData`
   * `appBarTheme` -> `AppBarThemeData` (Replace `color` with `backgroundColor`)
   * `bottomAppBarTheme` -> `BottomAppBarThemeData`
   * `inputDecorationTheme` -> `InputDecorationThemeData`

   ```dart
   ThemeData(
     colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
     appBarTheme: const AppBarThemeData(
       backgroundColor: Colors.blue, // Do not use 'color'
       elevation: 4.0,
     ),
     cardTheme: const CardThemeData(
       elevation: 2.0,
     ),
   );
   ```

5. **Migrate Buttons and Button Styles**
   Replace legacy buttons. Use the `styleFrom()` static method for simple overrides, or `ButtonStyle` with `MaterialStateProperty` for state-dependent styling.

   ```dart
   // Simple override using styleFrom
   TextButton(
     style: TextButton.styleFrom(
       foregroundColor: Colors.blue,
       disabledForegroundColor: Colors.red,
     ),
     onPressed: () {},
     child: const Text('TextButton'),
   )

   // State-dependent override using MaterialStateProperty
   OutlinedButton(
     style: ButtonStyle(
       side: MaterialStateProperty.resolveWith<BorderSide>(
         (Set<MaterialState> states) {
           if (states.contains(MaterialState.pressed)) {
             return const BorderSide(color: Colors.blue, width: 2);
           }
           return const BorderSide(color: Colors.grey, width: 1);
         }
       ),
     ),
     onPressed: () {},
     child: const Text('OutlinedButton'),
   )
   ```

6. **Decision Logic: Platform Idioms**
   Apply platform-specific adaptations based on the host OS to reduce cognitive load and build user trust.
   * **Scrollbars:** IF desktop platform -> Set `thumbVisibility: true` (or `alwaysShown`). IF mobile -> Use default auto-hiding behavior.
   * **Text Selection:** IF text is informational and non-interactive -> Wrap in `SelectableText` to allow mouse selection on Web/Desktop.
   * **Button Ordering:** IF Windows -> Place confirmation button on the LEFT. IF macOS/Linux/Android/iOS -> Place confirmation button on the RIGHT.

   ```dart
   // Platform-aware button ordering
   TextDirection btnDirection = Platform.isWindows 
       ? TextDirection.rtl 
       : TextDirection.ltr;

   Row(
     children: [
       const Spacer(),
       Row(
         textDirection: btnDirection,
         children: [
           TextButton(
             onPressed: () => Navigator.pop(context, false),
             child: const Text('Cancel'),
           ),
           ElevatedButton(
             onPressed: () => Navigator.pop(context, true),
             child: const Text('OK'),
           ),
         ],
       ),
     ],
   )
   ```

7. **Validate-and-Fix**
   Scan the generated code to verify that no `FlatButton`, `RaisedButton`, `OutlineButton`, or `ButtonTheme` classes remain. Verify that `AppBarTheme` does not use the `color` property. Fix any instances found.

## Constraints
* **Single Source of Truth:** All colors must be derived from the `ColorScheme` (e.g., `Theme.of(context).colorScheme.primary`). Do not hardcode hex colors unless explicitly requested.
* **No Legacy Buttons:** Never output `FlatButton`, `RaisedButton`, or `OutlineButton`.
* **No Accent Properties:** Never use `accentColor`, `accentColorBrightness`, `accentTextTheme`, or `accentIconTheme`. Use `colorScheme.secondary` and `colorScheme.onSecondary` instead.
* **Component Theme Suffixes:** Always append `Data` to component themes when configuring `ThemeData` (e.g., `CardThemeData`, not `CardTheme`).
* **AppBar Background:** Never use the `color` property in `AppBarTheme` or `AppBarThemeData`; strictly use `backgroundColor`.

