When I started developing in Flutter, I first had many doubts on how to use the buttons, how to customize them and I got puzzled on how to theme them!
So I had dug a bit and summarized the type of Buttons in this guide of flutter buttons.
In this post, I will try to provide all the necessary information to answer some questions.
What type of Flutter Button should I use? How can I customize my button? A FlatButton with elevations is the same as the RaisedButton?
First of all. Let me point out what are the differences among the common Flutter buttons and how they are related.
- FlatButton extends MaterialButton.
- RaisedButton extends MaterialButton.
- OutlineButton extends MaterialButton.
- MaterialButton builds RawMaterialButton.
- IconButton builds a ConstrainedBox with Inked Widget.
- RawMaterialButton builds a ConstrainedBox with Inked Widget.
MaterialButton
- It provides a default padding.
- It is disabled if onPressed parmeter is null. Automatically colored as grey.
FlatButton
It is a MaterialButton, basically there is no difference. But for clarity it is recommended to use FlatButton class.
RaisedButton
It is a MaterialButton with shadow/elevetation when pressed and colored background or gray if disabled.
OutlineButton
Same as FlatButton with a border grey line as shape by default.
To change the border color when pressed, use property highlightBorderColor.
To change the border color when is not pressed, you need to customize borderSide with BorderSide(color:Color.xxx)
Buttons with Icon
To add an icon we can use FlatButton.icon, RaisedButton.icon, OutlineButton.icon.
IconButton
It is just an Icon (no text). This Button is typically used on the AppBar.
Customize Buttons
For all the Buttons above you can customize the appearance individually using the following properties:
color: Background color for a Button. It will override any themed color provided.
FlatButton(color:Colors.cyan,child: Text("FlatButton"),onPressed: ()=>{},),
shape: It provides a shape of the button.
Another example:
FlatButton( color:Colors.cyan, shape: ContinuousRectangleBorder( side: BorderSide(color:Colors.cyan[900],width: 4), borderRadius: BorderRadius.circular(80.0)), child: Text("FlatButton"),onPressed: ()=>{},),
Theming Buttons
There are two classes that provide theming to buttons into our App. ThemeData and ButtonThemeData.
We can customize (coloring but no shape) Buttons using the following attributes in ThemeData.
- ThemeData.buttonColor: Default background color used by RaisedButtons. If not provided, the primarySwatch[600] is used (in some cases, see below).
💡 If you want to fill with color a FlatButton or OutlineButton then use parameter color when building the button.
- ThemeData.splashColor: Color to start filling the Buttons when pressed. (The ripple color in Android).
- ThemeData.highlightColor: Color used to fill the background when splash has ended.
- ThemeData.hoverColor: Color when the mouse passes over it. (Not visible on mobile native).
❗ ThemeData.brightness is important. It might change the color of the button. See examples in section Theme Buttons Table
ButtonThemeData
But wait! if you define a ButtonThemeData, all properties above can be overridden by ButtonThemeData.
It let us define some attributes, like:
- ButtonThemeData.buttonColor: Same as ThemeData.
- ButtonThemeData.splashColor: Same as ThemeData used in FlatButton, OutlineButton or RaisedButton.
- ButtonThemeData.highlightColor: Same as ThemeData.
- ButtonThemeData.hoverColor: Same as ThemeData.
- ButtonThemeData.minWidth: Default minimum width.
- ButtonThemeData.height: Default height.
- ButtonThemeData. padding: Default padding.
- ButtonThemeData.shape: Default shape.
Particularities using ThemeData and ButtonThemeData
It could not be that easy!
I found some issues on theming the buttons when trying some Google CodeLabs or creating my Apps… And this is why:
⚠️ If ButtonThemeData is provided, values from ThemeData won’t be taken into account at all!
⚠️So some things we need to keep in mind:
- buttonColor, splashColor,hoverColor,highlightColor from ThemeData will be used to build a ButtonThemeData internally (if none is provided) when calling constructor ThemeData().
- if you try to use ThemData.copyWith(buttonColor:..) the ButtonThemeData won’t be recreated using the buttonColor and you won’t have the desired result.
- buttonColor. The color used for background color in RaisedButton. If no defined , the theme color primarySwatch is used (If theme is light, grey if it is dark). Check the method ButtonThemeData.getFillColor to know how it is filled.
- For splashColor. ⚠️ Flat, Raised or OutlineButton define splashColor in ButtonThemeData.
For instance, observe the result if we have defined this ButtonThemeData in the Theming without providing a splashColor:
theme: ThemeData( primarySwatch: Colors.green, splashColor: Colors.pink, buttonTheme: ButtonThemeData( // splashColor:Colors.pink, //we don't define the splashColor in ButtonThemeDaa height:60 ) ),
The result:
You can customize all InkWell, Icon or MaterialButton in the App defining attributes in the ThemeData.
Watch out the ButtonBar
Let’s see what happens to wrap a RaisedButon and a FlatButton in the ButtonBar.
Umh 🤔. Why FlatButton in a ButtonBar uses another color? Yeah.. this is how is made ButtonBar. As we can read in the doc:
The children are wrapped in a ButtonTheme that is a copy of the surrounding ButtonTheme with the button properties overridden by the properties of the ButtonBar as described above.
This is giving us a clue about what is going on here. Fortunately, we can inspect all Flutter widgets since they are implemented in Dart.
Checking the code of ButtonBar, we spot that indeed the ButtonBar wraps the buttons in a new ButtonTheme copied from the one from the ThemeData (either built internally or the one provided by us). But it will override the ButtonTextTheme to use the ButtonTextTheme.primary, while the default value is ButtonTextTheme.normal.
So that is why the FlatButton shows in blue (in this example I have not provided a primarySwatch, so the default one is Colors.blue for a Theme).
Is this the desired behavior? Maybe… But it is confusing since it is also not consistent with Material.io Buttons
Theme Button Table
Here you can find some examples of different Theme setups and their results.
ThemeData( primarySwatch: Colors.red,
|
![]() |
ThemeData( primarySwatch: Colors.red, buttonTheme: ButtonThemeData()
|
![]() |
ThemeData( brightness: Brightness.dark, primarySwatch: Colors.red, buttonTheme: ButtonThemeData() //Empty ButtonThemeData //has no effect on dark Themes
|
![]() |
ThemeData( primarySwatch: Colors.red, buttonColor: Colors.red,
|
![]() |
ThemeData( buttonColor: Colors.red,
|
![]() |
ThemeData( primarySwatch: Colors.red, splashColor:Colors.pink buttonTheme: ButtonThemeData()
|
![]() |
ThemeData( primarySwatch: Colors.red, splashColor:Colors.pink buttonTheme: ButtonThemeData( splashColor:Colors.pink )
|
![]() |
Conclusion
Defining the primarySwatch in ThemeData is important to avoid undesired colors to appear.
Define buttonColor,splashColor,etc in ThemeData is not enough. It is usually needed to be defined as well in ButtonThemeData. Ideally in both.
Keep in mind ThemeData creates a ButtonThemeData internally with predefined values (explained above). So take this into account if you use ThemeData.copyWith() or similar.
I created this article because I had many doubts about what characteristics had each Button and I was not sure when/what/how to customize or theme.
Hope this little article helps you to use the Flutter Buttons in a better way.
If you find any error or you have suggestions, please let me know! I will be happy to learn and to correct any possible mistakes.
Happy Fluttering!