A Comprehensive Guide to Flutter Buttons: Choosing the Right One for Your App

joshua-reddekopp-syymxsdnj54-unsplash

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.

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

basic-textbutton-with-onpressed-function-enabled

Copy
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

disabled-textbutton-with-onpressed-function-set-to-null

Copy
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-with-icon-and-onpressed-function-enabled

Copy
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-with-custom-styling-and-onpressed-function-enabled

Copy
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-with-custom-shape-and-onpressed-function-enabled

Copy
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-with-custom-overlay-color-and-onpressed-function-enabled

Copy
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-with-custom-foreground-using-shadermask-and-onpressed-function-enabled

Copy
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-with-custom-background-and-onpressed-function-enabled

Copy
TextButton(
  style: TextButton.styleFrom(
    foregroundBuilder: (context, states, child) {
      return DecoratedBox(
        decoration: BoxDecoration(
          border: states.contains(MaterialState.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-with-custom-background-and-onpressed-function-enabled

Copy
TextButton(
  onPressed: () {}, // onPressed function that gets triggered when button is pressed
  style: TextButton.styleFrom(
    overlayColor: Colors.orange.withOpacity(
      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(MaterialState.pressed))
            ? BoxDecoration(
                gradient: LinearGradient(
                  colors: [
                    Colors.orange.withOpacity(
                      1.0,
                    ),
                    Colors.orange.withOpacity(
                      1.0,
                    ),
                  ],
                ), // Gradient when button is pressed
              )
            : BoxDecoration(
                gradient: LinearGradient(
                  colors: switch (
                      states.contains(MaterialState.hovered)) {
                    true => [
                        Colors.blue.withOpacity(
                          1.0,
                        ),
                        Colors.orange.withOpacity(
                          1.0,
                        )
                      ],
                    false => [
                        Colors.orange.withOpacity(
                          1.0,
                        ),
                        Colors.blue.withOpacity(
                          1.0,
                        ),
                      ],
                  },
                ), // Gradient when button is not pressed
              ),
        child: child,
      );
    },
  ).copyWith(
    side: MaterialStateProperty.resolveWith<BorderSide?>((states) {
      if (states.contains(MaterialState.hovered)) {
        return BorderSide(
          width: 3,
          color: Colors.yellow.withOpacity(
            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

a-filled-button-with-a-solid-background-color

Copy
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

a-tonal-filled-button-with-a-softer-less-prominent-background-color

Copy
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

an-elevatedbutton

Copy
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-with-a-custom-onpressed-callback

Copy
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

basic-icon-button-with-an-icon-and-onpressed-function

Copy
IconButton(
  icon: const Icon(Icons.filter_drama),
  onPressed: () {
    // Add your onPressed code here!
  },
),

Filled IconButton with an icon and onPressed function

filled-icon-button-with-an-icon-and-onpressed-function

Copy
IconButton.filled(
  onPressed: () {
    // Add your onPressed code here!
  },
  icon: const Icon(
    Icons.filter_drama,
  ),
),

Filled tonal IconButton with an icon and onPressed function

filled-tonal-icon-button-with-an-icon-and-onpressed-function

Copy
IconButton.filledTonal(
  onPressed: () {
    // Add your onPressed code here!
  },
  icon: const Icon(
    Icons.filter_drama,
  ),
),

Outlined IconButton with an icon and onPressed function

outlined-icon-button-with-an-icon-and-onpressed-function

Copy
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

small-floating-action-button-with-an-add-icon

Copy
FloatingActionButton.small(
  onPressed: () {
    // Add your onPressed code here!
  },
  child: const Icon(Icons.add),
),

Default size FloatingActionButton with an add icon

default-size-floating-action-button-with-an-add-icon

Copy
FloatingActionButton(
  onPressed: () {
    // Add your onPressed code here!
  },
  child: const Icon(Icons.add),
),

Large FloatingActionButton with an add icon

large-floating-action-button-with-an-add-icon

Copy
FloatingActionButton.large(
  onPressed: () {
    // Add your onPressed code here!
  },
  child: const Icon(Icons.add),
),

Extended FloatingActionButton with a label and an add icon

extended-floating-action-button-with-a-label-and-an-add-icon

Copy
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

a-disabled-cupertino-button-with-a-standard-transparent-background

Copy
const CupertinoButton(
  onPressed: null,
  child: Text('Disabled'),
),

A disabled filled Cupertino button with a solid background color

a-disabled-filled-cupertino-button-with-a-solid-background-color

Copy
const CupertinoButton.filled(
  onPressed: null,
  child: Text('Disabled'),
),

An enabled Cupertino button with a standard transparent background

an-enabled-cupertino-button-with-a-standard-transparent-background

Copy
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

an-enabled-filled-cupertino-button-with-a-solid-background-color

Copy
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!

Tags:

Check out more posts in my blogs