âš¡ TL;DR
Complete guide to Flutter Button widgets. Learn how to use ElevatedButton, TextButton, OutlinedButton, IconButton, CupertinoButton, and FAB with examples.
Are you a Flutter developer who’s ever felt puzzled by which button to use in your app’s UI? You’re not alone. Many developers struggle to pick the right button type, often resorting to unnecessary customizations. But fear not! This guide is here to demystify Flutter buttons, helping you make informed choices for your app’s design needs.
Version note (Nov 2026): All examples in this guide were tested on Flutter 3.3x with Material 3 enabled by default. The code uses the modern
WidgetStateenum (which replaced the deprecatedMaterialStatein Flutter 3.19+) andColor.withValues(alpha:)(which replacedwithOpacityin Flutter 3.27+). For the full API reference of every button class, see the official Flutter buttons documentation.
Flutter has six main button widgets, and each maps to a different emphasis level: TextButton for low-emphasis actions, FilledButton for important ones, ElevatedButton when you need elevation and prominence, OutlinedButton for medium emphasis, IconButton for icon-only actions, FloatingActionButton for the primary action of a screen, and CupertinoButton when you want an iOS-native look. Pick the widget that matches the action’s emphasis instead of styling one button type to imitate another.
TextButton:
The TextButton is your basic, no-frills button. It’s perfect for simple actions like navigating pages or confirming choices. Avoid adding unnecessary customizations to it. Let it blend seamlessly into your UI, or customize it with a style or theme if needed.
Basic TextButton with onPressed function enabled

TextButton(
// onPressed function that gets triggered when button is pressed
onPressed: () {
// Add your onPressed code here!
},
child: const Text(
'This is a TextButton Demo - Enabled',
), // Text displayed on the button
),Disabled TextButton with onPressed function set to null

TextButton(
// Button is disabled
// as onPressed function is null
onPressed: null,
child: Text(
'This is a TextButton Demo - Disabled',
),
),TextButton with icon and onPressed function enabled
![]()
TextButton.icon(
// onPressed function that gets
//triggered when button is pressed
onPressed: () {
// Add your onPressed code here!
},
icon: const Icon(
Icons.access_alarm,
), // Icon displayed before the text
label: const Text(
'This is a TextButton Demo - TextButton.icon #1',
), // Text displayed on the button
),TextButton with custom styling and onPressed function enabled

TextButton.icon(
style: TextButton.styleFrom(
foregroundColor: Colors.white, // Text color
backgroundColor: Colors.green, // Background color
),
onPressed: () {}, // onPressed function that gets triggered when button is pressed
icon: const Icon(
Icons.access_alarm,
), // Icon displayed before the text
label: const Text(
'This is a TextButton Demo - TextButton.icon #2',
), // Text displayed on the button
),TextButton with custom shape and onPressed function enabled

TextButton(
style: TextButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(
Radius.circular(
20,
),
), // Border radius of the button
side: BorderSide(
color: Colors.lightBlue, // Border color
width: 3, // Border width
),
),
),
onPressed: () {}, // onPressed function that gets triggered when button is pressed
child: const Text(
'This is a TextButton Demo - TextButton #3',
), // Text displayed on the button
),TextButton with custom overlay color and onPressed function enabled

TextButton(
style: TextButton.styleFrom(
overlayColor: Colors.amber, // Color when button is pressed
),
onPressed: () {}, // onPressed function that gets triggered when button is pressed
child: const Text(
'This is a TextButton Demo - TextButton #4',
), // Text displayed on the button
),TextButton with custom foreground using ShaderMask and onPressed function enabled

TextButton(
style: TextButton.styleFrom(
foregroundBuilder: (context, states, child) {
return ShaderMask(
shaderCallback: (Rect bounds) {
return LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.red,
Colors.green,
],
).createShader(bounds);
},
blendMode: BlendMode.srcATop,
child: child,
);
},
),
onPressed: () {}, // onPressed function that gets triggered when button is pressed
child: const Text(
'This is a TextButton Demo - TextButton #5',
), // Text displayed on the button
),TextButton with custom foreground using DecoratedBox and onPressed function enabled

TextButton(
style: TextButton.styleFrom(
foregroundBuilder: (context, states, child) {
return DecoratedBox(
decoration: BoxDecoration(
border: states.contains(WidgetState.hovered)
? Border(
bottom: BorderSide(
color: Colors.lightBlue,
),
)
: const Border(), // Border displayed when button is hovered
),
child: child,
);
},
),
onPressed: () {}, // onPressed function that gets triggered when button is pressed
child: const Text(
'This is a TextButton Demo - TextButton #6',
), // Text displayed on the button
),TextButton with custom background and onPressed function enabled

TextButton(
onPressed: () {}, // onPressed function that gets triggered when button is pressed
style: TextButton.styleFrom(
overlayColor: Colors.orange.withValues(
alpha: 1.0,
), // Color when button is pressed
backgroundBuilder: (context, states, child) {
return AnimatedContainer(
duration: const Duration(
milliseconds: 500,
), // Duration of the animation
decoration: (states.contains(WidgetState.pressed))
? BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.orange.withValues(
alpha: 1.0,
),
Colors.orange.withValues(
alpha: 1.0,
),
],
), // Gradient when button is pressed
)
: BoxDecoration(
gradient: LinearGradient(
colors: switch (
states.contains(WidgetState.hovered)) {
true => [
Colors.blue.withValues(
alpha: 1.0,
),
Colors.orange.withValues(
alpha: 1.0,
)
],
false => [
Colors.orange.withValues(
alpha: 1.0,
),
Colors.blue.withValues(
alpha: 1.0,
),
],
},
), // Gradient when button is not pressed
),
child: child,
);
},
).copyWith(
side: WidgetStateProperty.resolveWith<BorderSide?>((states) {
if (states.contains(WidgetState.hovered)) {
return BorderSide(
width: 3,
color: Colors.yellow.withValues(
alpha: 1.0,
), // Border color when button is hovered
);
}
return null; // Border color when button is not hovered
}),
),
child: const Text(
'TextButton #7',
style: TextStyle(
color: Colors.white,
),
), // Text displayed on the button
),FilledButton:
Consider FilledButton as a TextButton with a bit more flair. It’s great for important actions that demand attention, like saving or confirming. While it offers tonal variations, remember, it’s essentially a styled TextButton.
A filled button with a solid background color

FilledButton(
onPressed: () {
// Define the action that should be taken when the button is pressed.
// Currently, this is an empty function.
},
child: const Text(
"This is a filled button - Mihir Pipermitwala",
),
),A tonal filled button with background color

FilledButton.tonal(
onPressed: () {
// Define the action that should be taken when the button is pressed.
// Currently, this is an empty function.
},
child: const Text(
"This is a filled button (tonal)",
),
)ElevatedButton:
ElevatedButton adds depth to your UI with its elevation and native Android-like appearance. Use it when you want your button to stand out or convey hierarchy. But avoid using it in popups or dialogues where default animations might clash.
A Disabled ElevatedButton with custom text style

ElevatedButton(
onPressed: null,
child: const Text(
'Disabled',
),
),
ElevatedButton(
onPressed: () {
// Add your onPressed code here!
},
child: const Text(
'Enabled',
),
),OutlinedButton:
If you need a button with a subtle outline, OutlinedButton is your friend. It’s ideal for medium-emphasis actions. Its clean design ensures it doesn’t overpower your UI elements.
OutlinedButton with a custom onPressed callback

OutlinedButton(
onPressed: () {
debugPrint(
'Received click',
);
},
child: const Text(
'Click Me',
),
),IconButton:
Need a button with just an icon? IconButton is the way to go. It offers click animations and various button styles, making it versatile for different UI needs.
Basic IconButton with an icon and onPressed function
![]()
IconButton(
icon: const Icon(Icons.filter_drama),
onPressed: () {
// Add your onPressed code here!
},
),Filled IconButton with an icon and onPressed function
![]()
IconButton.filled(
onPressed: () {
// Add your onPressed code here!
},
icon: const Icon(
Icons.filter_drama,
),
),Filled tonal IconButton with an icon and onPressed function
![]()
IconButton.filledTonal(
onPressed: () {
// Add your onPressed code here!
},
icon: const Icon(
Icons.filter_drama,
),
),Outlined IconButton with an icon and onPressed function
![]()
IconButton.outlined(
onPressed: () {
// Add your onPressed code here!
},
icon: const Icon(
Icons.filter_drama,
),
),
FloatingActionButton:
The FloatingActionButton (FAB) widget is a circular button that floats above the content in a Flutter application. It is typically used for a primary action in an application.
Small FloatingActionButton with an add icon
![]()
FloatingActionButton.small(
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.add),
),
Default size FloatingActionButton with an add icon
![]()
FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.add),
),Large FloatingActionButton with an add icon
![]()
FloatingActionButton.large(
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.add),
),Extended FloatingActionButton with a label and an add icon
![]()
FloatingActionButton.extended(
onPressed: () {
// Add your onPressed code here!
},
label: const Text('Add'),
icon: const Icon(Icons.add),
),CupertinoButton:
CupertinoButton brings an iOS-native button design to your Flutter app. Use it for a seamless iOS experience, complete with default iOS animations and padding.
A disabled Cupertino button with a standard transparent background

const CupertinoButton(
onPressed: null,
child: Text('Disabled'),
),A disabled filled Cupertino button with a solid background color

const CupertinoButton.filled(
onPressed: null,
child: Text('Disabled'),
),An enabled Cupertino button with a standard transparent background

CupertinoButton(
onPressed: () {
// Define the action that should be taken when the button is pressed.
},
child: const Text('Enabled'),
),An enabled filled Cupertino button with a solid background color

CupertinoButton.filled(
onPressed: () {
// Define the action that should be taken when the button is pressed.
},
child: const Text('Enabled'),
),Summary
Each Flutter button serves a specific purpose in your UI arsenal. Choose wisely based on your app’s needs, and remember, simplicity is often key. Have questions or suggestions? Drop them in the comments below. And if you found this guide helpful, don’t forget to show some love by hitting that clap button!
Related Posts
- How to Change minSdkVersion in Flutter: 2 Simple Approaches
- Enhancing File Manipulation in Flutter: Best Practices and Examples
- Flutter Debug Banner Removal: Best Practices and Techniques
- How to Show Automatic Internet Connection Offline Message in Flutter
References
- ButtonStyle.styleFrom — Flutter API docs
- ButtonStyle class — Flutter API docs
- WidgetState enum — Flutter API docs
- CupertinoButton class — Flutter API docs
- FloatingActionButton class — Flutter API docs
- Material 3 button guide — Flutter docs
FAQ
What are the different types of buttons in Flutter?
Flutter’s Material library ships six main button widgets: TextButton for low-emphasis actions, FilledButton for important confirmations, ElevatedButton when you want prominence and shadow, OutlinedButton for medium emphasis, IconButton for icon-only actions, and FloatingActionButton for a screen’s primary action. CupertinoButton adds a seventh option that mimics native iOS styling and animations.
When should I use TextButton instead of ElevatedButton in Flutter?
Use TextButton for secondary, low-emphasis actions such as navigation links, cancel buttons, or inline confirmations where a solid background would visually compete with more important actions. ElevatedButton suits primary actions that should stand out with elevation and a filled background. Match the widget to the action’s emphasis rather than restyling one button to imitate another.
How do I change the background color of a Flutter button?
Call the button’s static styleFrom method and pass a backgroundColor. For example, TextButton.styleFrom(backgroundColor: Colors.green) sets a custom background color on a TextButton, and equivalent styleFrom factories exist for FilledButton, ElevatedButton, and OutlinedButton. You can also set foregroundColor for the text or label color in the same call.
What is the difference between FilledButton and FilledButton.tonal in Flutter?
FilledButton renders a solid, high-contrast background for the most prominent actions on a screen, while FilledButton.tonal uses a softer, less prominent container color derived from the theme’s secondary palette. The tonal variant is a middle ground: more noticeable than an outlined button, but visually quieter than a fully filled one.

Written by Mihir Pipermitwala
Senior Full Stack Consultant & Mobile Engineering Specialist building user-focused applications in healthcare with Flutter, Dart and React Native. I write about what I actually build and test — every tutorial here comes from real project work.
More about Mihir →