Skip to content

Changing Elevated Button Background Color in Flutter

Learn how to properly customize the background color of ElevatedButton widgets in Flutter using modern approaches and best practices.

Problem Statement

When working with Flutter's ElevatedButton, developers often encounter errors when trying to customize the button's background color. The common error occurs:

type '_MaterialStatePropertyAll' is not a subtype of type 'MaterialStateProperty<Color?>?

This typically happens when:

  1. Using the wrong approach to set button colors
  2. Passing incorrect parameter types to styling properties
  3. Not accounting for Flutter version changes in the API

Solution Overview

Flutter provides several methods to customize ElevatedButton colors. The two primary approaches are:

  1. Using ElevatedButton.styleFrom() - Simplified approach for basic customization
  2. Using ButtonStyle with MaterialStateProperty - More control over different button states

The simplest and most straightforward approach for most use cases:

dart
ElevatedButton(
  onPressed: () {},
  child: Text('Click Me'),
  style: ElevatedButton.styleFrom(
    backgroundColor: Colors.blue,    // Background color
    foregroundColor: Colors.white,    // Text/icon color
    padding: EdgeInsets.all(16.0),
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(8.0),
    ),
  ),
)

Method 2: Using ButtonStyle with MaterialStateProperty

For more advanced control over different button states (pressed, disabled, hovered, etc.):

dart
ElevatedButton(
  onPressed: () {},
  child: Text('Click Me'),
  style: ButtonStyle(
    backgroundColor: MaterialStateProperty.resolveWith<Color>(
      (Set<MaterialState> states) {
        if (states.contains(MaterialState.pressed)) {
          return Colors.blue.shade700; // Color when pressed
        } else if (states.contains(MaterialState.disabled)) {
          return Colors.grey; // Color when disabled
        }
        return Colors.blue; // Default color
      },
    ),
    foregroundColor: MaterialStateProperty.all(Colors.white),
  ),
)

Method 3: Dynamic Color Changes Based on State

For buttons that need to change color based on application state:

dart
bool _isActive = false;

ElevatedButton(
  onPressed: () {
    setState(() {
      _isActive = !_isActive;
    });
  },
  child: Text(_isActive ? 'Active' : 'Inactive'),
  style: ElevatedButton.styleFrom(
    backgroundColor: _isActive ? Colors.green : Colors.red,
    foregroundColor: Colors.white,
  ),
)

Common Pitfalls and Solutions

WARNING

Important Version Note: As of Flutter v3.1.0, the primary parameter in ElevatedButton.styleFrom() is deprecated. Use backgroundColor instead.

Incorrect approach (deprecated):

dart
// ❌ Don't use - deprecated after Flutter v3.1.0
ElevatedButton.styleFrom(primary: Colors.red)

Correct approach:

dart
// ✅ Use this instead
ElevatedButton.styleFrom(backgroundColor: Colors.red)

TIP

Always ensure your onPressed callback is properly defined. Buttons without an onPressed handler will appear disabled with gray colors regardless of your custom styling.

Complete Example: Xylophone App Buttons

Here's the corrected implementation for the xylophone application mentioned in the question:

dart
void playSound(int soundNumber) {
  final player = AudioCache();
  player.play('note$soundNumber.wav');
}

Expanded buildPlayButton({required Color color, required int soundNumber}) {
  return Expanded(
    child: ElevatedButton(
      onPressed: () {
        playSound(soundNumber);
      },
      style: ElevatedButton.styleFrom(
        backgroundColor: color,
        foregroundColor: Colors.white,
      ),
    ),
  );
}

// Usage in build method
Widget build(BuildContext context) {
  return Column(
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: <Widget>[
      buildPlayButton(color: Colors.red, soundNumber: 1),
      buildPlayButton(color: Colors.orange, soundNumber: 2),
      buildPlayButton(color: Colors.yellow, soundNumber: 3),
      buildPlayButton(color: Colors.green, soundNumber: 4),
      buildPlayButton(color: Colors.blue, soundNumber: 5),
      buildPlayButton(color: Colors.indigo, soundNumber: 6),
      buildPlayButton(color: Colors.purple, soundNumber: 7),
    ],
  );
}

Additional Styling Options

Beyond background color, you can customize various aspects of ElevatedButton:

dart
ElevatedButton(
  onPressed: () {},
  child: Text('Styled Button'),
  style: ElevatedButton.styleFrom(
    backgroundColor: Colors.deepPurple,
    foregroundColor: Colors.white,
    elevation: 5,
    shadowColor: Colors.deepPurple.shade300,
    padding: EdgeInsets.symmetric(horizontal: 32, vertical: 16),
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(20),
    ),
    textStyle: TextStyle(
      fontSize: 18,
      fontWeight: FontWeight.bold,
    ),
  ),
)

Best Practices

  1. Use styleFrom() for simple customizations - It's more concise and readable
  2. Use ButtonStyle for state-dependent styling - When you need different colors for pressed, hovered, or disabled states
  3. Ensure contrast between background and text colors - For accessibility
  4. Test your buttons in different states - Especially disabled and pressed states
  5. Consider using theme colors - For consistency across your app
dart
// Using theme colors
ElevatedButton(
  onPressed: () {},
  child: Text('Themed Button'),
  style: ElevatedButton.styleFrom(
    backgroundColor: Theme.of(context).primaryColor,
    foregroundColor: Theme.of(context).colorScheme.onPrimary,
  ),
)

By following these approaches, you can effectively customize ElevatedButton colors in your Flutter applications while avoiding common pitfalls and ensuring your code remains maintainable across Flutter version updates.