flutter-theming-apps

Global styling and adaptive design patterns for Flutter apps using Material 3 theming. Covers Material 3 color schemes, typography, elevation, and modern component replacements (NavigationBar, FilledButton, SegmentedButton) Includes component theme normalization using *ThemeData classes and deprecation guidance for legacy properties like accentColor and AppBarTheme.color Provides platform-specific adaptive patterns: scrollbar visibility, selectable text, button order (Windows vs. macOS/Linux), and hover interactions Includes workflows for migrating legacy themes to Material 3 and implementing cross-platform UI components with state-dependent styling

INSTALLATION
npx skills add https://github.com/flutter/skills --skill flutter-theming-apps
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

$2a

Material 3 Guidelines

Material 3 is the default theme as of Flutter 3.16.

  • Colors: Generate color schemes using ColorScheme.fromSeed(seedColor: Colors.blue). This ensures accessible contrast ratios.
  • Elevation: Material 3 uses ColorScheme.surfaceTint to indicate elevation instead of just drop shadows. To revert to M2 shadow behavior, set surfaceTint: Colors.transparent and define a shadowColor.
  • Typography: Material 3 updates font sizes, weights, and line heights. If text wrapping breaks legacy layouts, adjust letterSpacing on the specific TextStyle.
  • Modern Components:
  • Replace BottomNavigationBar with NavigationBar.
  • Replace Drawer with NavigationDrawer.
  • Replace ToggleButtons with SegmentedButton.
  • Use FilledButton for a high-emphasis button without the elevation of ElevatedButton.

Component Theme Normalization

Component themes in ThemeData have been normalized to use *ThemeData classes rather than *Theme widgets.

When defining ThemeData, strictly use the *ThemeData suffix for the following properties:

  • cardTheme: Use CardThemeData (Not CardTheme)
  • dialogTheme: Use DialogThemeData (Not DialogTheme)
  • tabBarTheme: Use TabBarThemeData (Not TabBarTheme)
  • appBarTheme: Use AppBarThemeData (Not AppBarTheme)
  • bottomAppBarTheme: Use BottomAppBarThemeData (Not BottomAppBarTheme)
  • inputDecorationTheme: Use InputDecorationThemeData (Not InputDecorationTheme)

Button Styling

Legacy button classes (FlatButton, RaisedButton, OutlineButton) are obsolete.

  • Use TextButton, ElevatedButton, and OutlinedButton.
  • Configure button appearance using a ButtonStyle object.
  • For simple overrides based on the theme's color scheme, use the static utility method: TextButton.styleFrom(foregroundColor: Colors.blue).
  • For state-dependent styling (hovered, focused, pressed, disabled), use MaterialStateProperty.resolveWith.

Platform Idioms & Adaptive Design

When building adaptive apps, respect platform-specific norms to reduce cognitive load and build user trust.

  • Scrollbars: Desktop users expect omnipresent scrollbars; mobile users expect them only during scrolling. Toggle thumbVisibility on the Scrollbar widget based on the platform.
  • Selectable Text: Web and desktop users expect text to be selectable. Wrap text in SelectableText or SelectableText.rich.
  • Horizontal Button Order: Windows places confirmation buttons on the left; macOS/Linux place them on the right. Use a Row with TextDirection.rtl for Windows and TextDirection.ltr for others.
  • Context Menus & Tooltips: Desktop users expect hover and right-click interactions. Implement Tooltip for hover states and use context menu packages for right-click actions.

Workflows

Workflow: Migrating Legacy Themes to Material 3

Use this workflow when updating an older Flutter codebase.

Task Progress:

  • 1. Remove useMaterial3: false from ThemeData (it is true by default).
  • 2. Replace manual ColorScheme definitions with ColorScheme.fromSeed().
  • 3. Run validator -> review errors -> fix: Search for and replace deprecated accentColor, accentColorBrightness, accentIconTheme, and accentTextTheme.
  • 4. Run validator -> review errors -> fix: Search for AppBarTheme(color: ...) and replace with backgroundColor.
  • 5. Update ThemeData component properties to use *ThemeData classes (e.g., cardTheme: CardThemeData()).
  • 6. Replace legacy buttons (FlatButton -> TextButton, RaisedButton -> ElevatedButton, OutlineButton -> OutlinedButton).
  • 7. Replace legacy navigation components (BottomNavigationBar -> NavigationBar, Drawer -> NavigationDrawer).

Workflow: Implementing Adaptive UI Components

Use this workflow when building a widget intended for both mobile and desktop/web.

Task Progress:

  • 1. If displaying a list/grid, wrap it in a Scrollbar and set thumbVisibility: DeviceType.isDesktop.
  • 2. If displaying read-only data, use SelectableText instead of Text.
  • 3. If implementing a dialog with action buttons, check the platform. If Windows, set TextDirection.rtl on the button Row.
  • 4. If implementing interactive elements, wrap them in Tooltip widgets to support mouse hover states.

Examples

Example: Modern Material 3 ThemeData Setup

MaterialApp(

  title: 'Adaptive App',

  theme: ThemeData(

    colorScheme: ColorScheme.fromSeed(

      seedColor: Colors.deepPurple,

      brightness: Brightness.light,

    ),

    // Use *ThemeData classes for component normalization

    appBarTheme: const AppBarThemeData(

      backgroundColor: Colors.deepPurple, // Do not use 'color'

      elevation: 0,

    ),

    cardTheme: const CardThemeData(

      elevation: 2,

    ),

    textTheme: const TextTheme(

      bodyMedium: TextStyle(letterSpacing: 0.2),

    ),

  ),

  home: const MyHomePage(),

);

Example: State-Dependent ButtonStyle

TextButton(

  style: ButtonStyle(

    // Default color

    foregroundColor: MaterialStateProperty.all<Color>(Colors.blue),

    // State-dependent overlay color

    overlayColor: MaterialStateProperty.resolveWith<Color?>(

      (Set<MaterialState> states) {

        if (states.contains(MaterialState.hovered)) {

          return Colors.blue.withOpacity(0.04);

        }

        if (states.contains(MaterialState.focused) || states.contains(MaterialState.pressed)) {

          return Colors.blue.withOpacity(0.12);

        }

        return null; // Defer to the widget's default.

      },

    ),

  ),

  onPressed: () {},

  child: const Text('Adaptive Button'),

)

Example: Adaptive Dialog Button Order

Row(

  // Windows expects confirmation on the left (RTL reverses the standard LTR Row)

  textDirection: Platform.isWindows ? TextDirection.rtl : TextDirection.ltr,

  mainAxisAlignment: MainAxisAlignment.end,

  children: [

    TextButton(

      onPressed: () => Navigator.pop(context, false),

      child: const Text('Cancel'),

    ),

    FilledButton(

      onPressed: () => Navigator.pop(context, true),

      child: const Text('Confirm'),

    ),

  ],

)
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card