Popular Searches
Popular Course Categories
Popular Courses

ElevatedButton, TextButton, and OutlinedButton

ElevatedButton, TextButton, and OutlinedButton

Flutter UI Components

Flutter ElevatedButton, TextButton, and OutlinedButton

Flutter provides several Material Design button widgets for handling user interactions. Among the most commonly used are ElevatedButton, TextButton, and OutlinedButton. Each button has a different visual style and is suitable for different types of actions.

These buttons are based on Flutter's ButtonStyle system, which allows developers to customize colors, padding, shape, elevation, text style, borders, sizes, and interaction states such as pressed, hovered, focused, and disabled.


1. What is a Button in Flutter?

A button is an interactive widget that allows the user to perform an action when tapped or activated.

Common button actions include:

  • Submitting a form
  • Opening another screen
  • Saving data
  • Deleting an item
  • Canceling an operation
  • Opening a dialog
  • Performing calculations
  • Calling an API

The basic structure of a Flutter button is:

ElevatedButton(
  onPressed: () {
    // Action
  },
  child: const Text('Click Me'),
)

The onPressed callback determines what happens when the button is activated. If both onPressed and onLongPress are null, the button becomes disabled.


2. Main Flutter Button Types

Button Appearance Common Use
ElevatedButton Filled/elevated appearance Primary actions
TextButton Text without visible border or fill Low-emphasis and secondary actions
OutlinedButton Visible border with transparent/low-fill appearance Secondary actions and alternatives

Flutter's Material Design button system also includes FilledButton and FilledButton.tonal, but this lesson focuses on ElevatedButton, TextButton, and OutlinedButton.


3. ElevatedButton

ElevatedButton is a Material Design button with a filled appearance and elevation. It is commonly used for important or primary actions in an application.

Basic ElevatedButton Example

ElevatedButton(
  onPressed: () {
    print('Button pressed');
  },
  child: const Text('Submit'),
)

How ElevatedButton Works

  • onPressed: Defines the action performed when the button is pressed.
  • child: Defines the button content.
  • style: Allows customization of the button's appearance.
  • onLongPress: Handles long-press interaction.
  • onHover: Handles pointer hover events on supported platforms.
  • onFocusChange: Detects focus changes.

ElevatedButton with Background and Text Color

ElevatedButton(
  onPressed: () {
    print('Login clicked');
  },
  style: ElevatedButton.styleFrom(
    backgroundColor: Colors.blue,
    foregroundColor: Colors.white,
  ),
  child: const Text('Login'),
)

ElevatedButton with Padding

ElevatedButton(
  onPressed: () {},
  style: ElevatedButton.styleFrom(
    padding: const EdgeInsets.symmetric(
      horizontal: 30,
      vertical: 15,
    ),
  ),
  child: const Text('Continue'),
)

ElevatedButton with Rounded Corners

ElevatedButton(
  onPressed: () {},
  style: ElevatedButton.styleFrom(
    backgroundColor: Colors.green,
    foregroundColor: Colors.white,
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(12),
    ),
  ),
  child: const Text('Save'),
)

ElevatedButton with Elevation

ElevatedButton(
  onPressed: () {},
  style: ElevatedButton.styleFrom(
    elevation: 5,
    backgroundColor: Colors.deepPurple,
    foregroundColor: Colors.white,
  ),
  child: const Text('Click Me'),
)

ElevatedButton with Icon

ElevatedButton.icon(
  onPressed: () {
    print('Download started');
  },
  icon: const Icon(Icons.download),
  label: const Text('Download'),
)

ElevatedButton for Login

ElevatedButton(
  onPressed: () {
    print('Login successful');
  },
  style: ElevatedButton.styleFrom(
    minimumSize: const Size(double.infinity, 50),
  ),
  child: const Text('Login'),
)

When to Use ElevatedButton

  • Login
  • Register
  • Submit
  • Save
  • Continue
  • Checkout
  • Confirm
  • Download

4. TextButton

TextButton is a low-emphasis button that normally appears as text without a visible border or filled background. It is useful for secondary actions, toolbar actions, dialogs, and inline actions.

Basic TextButton Example

TextButton(
  onPressed: () {
    print('Cancel clicked');
  },
  child: const Text('Cancel'),
)

TextButton with Text Color

TextButton(
  onPressed: () {},
  style: TextButton.styleFrom(
    foregroundColor: Colors.blue,
  ),
  child: const Text('Learn More'),
)

TextButton with Background Color

TextButton(
  onPressed: () {},
  style: TextButton.styleFrom(
    foregroundColor: Colors.white,
    backgroundColor: Colors.blue,
  ),
  child: const Text('Open'),
)

TextButton with Rounded Corners

TextButton(
  onPressed: () {},
  style: TextButton.styleFrom(
    foregroundColor: Colors.blue,
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(10),
    ),
  ),
  child: const Text('View Details'),
)

TextButton with Icon

TextButton.icon(
  onPressed: () {
    print('Edit clicked');
  },
  icon: const Icon(Icons.edit),
  label: const Text('Edit'),
)

TextButton in a Dialog

AlertDialog(
  title: const Text('Delete Item'),
  content: const Text('Are you sure you want to delete this item?'),
  actions: [
    TextButton(
      onPressed: () {
        print('Cancelled');
      },
      child: const Text('Cancel'),
    ),
    TextButton(
      onPressed: () {
        print('Deleted');
      },
      child: const Text('Delete'),
    ),
  ],
)

When to Use TextButton

  • Cancel
  • Skip
  • Learn More
  • View Details
  • Edit
  • Forgot Password
  • Dialog actions
  • Toolbar actions

5. OutlinedButton

OutlinedButton is a button with a visible border and no prominent filled background by default. It is useful when an action should be noticeable but visually less prominent than a primary filled button.

Basic OutlinedButton Example

OutlinedButton(
  onPressed: () {
    print('Outlined button clicked');
  },
  child: const Text('Cancel'),
)

OutlinedButton with Border Color

OutlinedButton(
  onPressed: () {},
  style: OutlinedButton.styleFrom(
    side: const BorderSide(
      color: Colors.blue,
      width: 2,
    ),
  ),
  child: const Text('View Profile'),
)

OutlinedButton with Rounded Corners

OutlinedButton(
  onPressed: () {},
  style: OutlinedButton.styleFrom(
    side: const BorderSide(
      color: Colors.blue,
    ),
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(12),
    ),
  ),
  child: const Text('Register'),
)

OutlinedButton with Background Color

OutlinedButton(
  onPressed: () {},
  style: OutlinedButton.styleFrom(
    foregroundColor: Colors.blue,
    backgroundColor: Colors.blue.shade50,
    side: const BorderSide(
      color: Colors.blue,
    ),
  ),
  child: const Text('Details'),
)

OutlinedButton with Icon

OutlinedButton.icon(
  onPressed: () {
    print('Upload clicked');
  },
  icon: const Icon(Icons.upload),
  label: const Text('Upload'),
)

When to Use OutlinedButton

  • Cancel
  • Register
  • View Details
  • Choose Option
  • Secondary navigation
  • Alternative actions
  • Upload
  • Filter

6. Difference Between ElevatedButton, TextButton, and OutlinedButton

Feature ElevatedButton TextButton OutlinedButton
Default Fill Filled/elevated appearance Transparent Generally transparent
Border Usually no visible border No visible border Visible border
Elevation Yes No prominent elevation No prominent elevation
Emphasis High Low Medium
Typical Use Primary action Secondary/inline action Secondary action
Example Submit Cancel View Details

7. ButtonStyle

Flutter provides ButtonStyle for controlling the visual appearance of buttons. It can be used with ElevatedButton, TextButton, OutlinedButton, and other Material buttons.

Common ButtonStyle properties include:

  • backgroundColor
  • foregroundColor
  • overlayColor
  • elevation
  • padding
  • minimumSize
  • fixedSize
  • maximumSize
  • side
  • shape
  • textStyle
  • iconColor
  • iconSize

ButtonStyle Example

ElevatedButton(
  onPressed: () {},
  style: ButtonStyle(
    backgroundColor: WidgetStatePropertyAll(Colors.blue),
    foregroundColor: WidgetStatePropertyAll(Colors.white),
    padding: WidgetStatePropertyAll(
      EdgeInsets.symmetric(
        horizontal: 25,
        vertical: 15,
      ),
    ),
    shape: WidgetStatePropertyAll(
      RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(10),
      ),
    ),
  ),
  child: const Text('Submit'),
)

For simple customization, styleFrom() is usually easier to read. For more detailed state-dependent styling, use ButtonStyle with widget-state properties.


8. Using styleFrom()

Flutter provides convenient styleFrom() methods for buttons. They allow developers to create a ButtonStyle using simple values.

ElevatedButton styleFrom

ElevatedButton(
  onPressed: () {},
  style: ElevatedButton.styleFrom(
    backgroundColor: Colors.green,
    foregroundColor: Colors.white,
    padding: const EdgeInsets.all(16),
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(10),
    ),
  ),
  child: const Text('Save'),
)

TextButton styleFrom

TextButton(
  onPressed: () {},
  style: TextButton.styleFrom(
    foregroundColor: Colors.blue,
    padding: const EdgeInsets.symmetric(
      horizontal: 20,
      vertical: 12,
    ),
  ),
  child: const Text('Learn More'),
)

OutlinedButton styleFrom

OutlinedButton(
  onPressed: () {},
  style: OutlinedButton.styleFrom(
    foregroundColor: Colors.blue,
    side: const BorderSide(
      color: Colors.blue,
      width: 2,
    ),
  ),
  child: const Text('View Profile'),
)

9. Button Width and Height

You can control button dimensions using properties such as minimumSize, fixedSize, and maximumSize.

Full Width Button

ElevatedButton(
  onPressed: () {},
  style: ElevatedButton.styleFrom(
    minimumSize: const Size(double.infinity, 50),
  ),
  child: const Text('Login'),
)

Fixed Size Button

OutlinedButton(
  onPressed: () {},
  style: OutlinedButton.styleFrom(
    fixedSize: const Size(200, 50),
  ),
  child: const Text('Continue'),
)

10. Button Padding

Padding creates space between the button's content and its boundary.

ElevatedButton(
  onPressed: () {},
  style: ElevatedButton.styleFrom(
    padding: const EdgeInsets.symmetric(
      horizontal: 30,
      vertical: 16,
    ),
  ),
  child: const Text('Submit'),
)

11. Button Shape

Buttons can be customized using different shapes.

Rounded Rectangle

ElevatedButton(
  onPressed: () {},
  style: ElevatedButton.styleFrom(
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(20),
    ),
  ),
  child: const Text('Rounded'),
)

Pill-Shaped Button

ElevatedButton(
  onPressed: () {},
  style: ElevatedButton.styleFrom(
    shape: const StadiumBorder(),
  ),
  child: const Text('Pill Button'),
)

12. Button with Icons

Flutter provides .icon constructors for several button types.

ElevatedButton with Icon

ElevatedButton.icon(
  onPressed: () {},
  icon: const Icon(Icons.save),
  label: const Text('Save'),
)

TextButton with Icon

TextButton.icon(
  onPressed: () {},
  icon: const Icon(Icons.edit),
  label: const Text('Edit'),
)

OutlinedButton with Icon

OutlinedButton.icon(
  onPressed: () {},
  icon: const Icon(Icons.delete),
  label: const Text('Delete'),
)

13. Disabled Buttons

A button becomes disabled when its action callback is null.

Disabled ElevatedButton

ElevatedButton(
  onPressed: null,
  child: const Text('Disabled'),
)

Disabled TextButton

TextButton(
  onPressed: null,
  child: const Text('Disabled'),
)

Disabled OutlinedButton

OutlinedButton(
  onPressed: null,
  child: const Text('Disabled'),
)

Disabled states are useful when an action should not be available until a required condition is satisfied.


14. Conditional Button State

Buttons can be enabled or disabled based on application state.

bool isFormValid = true;

ElevatedButton(
  onPressed: isFormValid
      ? () {
          print('Form submitted');
        }
      : null,
  child: const Text('Submit'),
)

This approach is commonly used in forms where the submit button should only become active after valid input is provided.


15. Buttons in a Row

Row(
  mainAxisAlignment: MainAxisAlignment.center,
  children: [
    ElevatedButton(
      onPressed: () {},
      child: const Text('Save'),
    ),
    const SizedBox(width: 10),
    OutlinedButton(
      onPressed: () {},
      child: const Text('Cancel'),
    ),
  ],
)

16. Login Screen Example

import 'package:flutter/material.dart';

class LoginPage extends StatelessWidget {
  const LoginPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Login'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          children: [
            const TextField(
              decoration: InputDecoration(
                labelText: 'Email',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 15),
            const TextField(
              obscureText: true,
              decoration: InputDecoration(
                labelText: 'Password',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                print('Login clicked');
              },
              style: ElevatedButton.styleFrom(
                minimumSize: const Size(
                  double.infinity,
                  50,
                ),
              ),
              child: const Text('Login'),
            ),
            TextButton(
              onPressed: () {
                print('Forgot password clicked');
              },
              child: const Text('Forgot Password?'),
            ),
            OutlinedButton(
              onPressed: () {
                print('Create account clicked');
              },
              child: const Text('Create Account'),
            ),
          ],
        ),
      ),
    );
  }
}

17. Save, Cancel, and Delete Example

Row(
  mainAxisAlignment: MainAxisAlignment.end,
  children: [
    TextButton(
      onPressed: () {
        print('Cancel');
      },
      child: const Text('Cancel'),
    ),
    OutlinedButton(
      onPressed: () {
        print('Delete');
      },
      child: const Text('Delete'),
    ),
    const SizedBox(width: 8),
    ElevatedButton(
      onPressed: () {
        print('Save');
      },
      child: const Text('Save'),
    ),
  ],
)

This arrangement demonstrates how different visual emphasis levels can be used for different actions.


18. Navigation Using Buttons

Buttons can be used to navigate between screens using Navigator.

ElevatedButton(
  onPressed: () {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => const SecondPage(),
      ),
    );
  },
  child: const Text('Open Next Page'),
)

Second Page

class SecondPage extends StatelessWidget {
  const SecondPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Second Page'),
      ),
      body: Center(
        child: TextButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: const Text('Go Back'),
        ),
      ),
    );
  }
}

19. Button Interaction States

Flutter buttons can have different visual states depending on user interaction.

State Description
Enabled The button can be activated.
Disabled The button cannot be activated.
Pressed The user is currently pressing the button.
Hovered A pointer is positioned over the button.
Focused The button has keyboard or accessibility focus.
Selected Used when an application needs a selected interaction state.

Flutter's widget-state properties can resolve different values depending on states such as pressed, hovered, focused, and disabled.


20. State-Dependent Button Styling

For advanced UI designs, ButtonStyle can use WidgetStateProperty to change styling according to the button's current state.

ElevatedButton(
  onPressed: () {},
  style: ButtonStyle(
    backgroundColor: WidgetStateProperty.resolveWith(
      (states) {
        if (states.contains(WidgetState.pressed)) {
          return Colors.green;
        }
        if (states.contains(WidgetState.hovered)) {
          return Colors.blue;
        }
        return Colors.indigo;
      },
    ),
  ),
  child: const Text('Interactive Button'),
)

This allows developers to create buttons that respond visually to user interaction.


21. Global Button Theme

If the same button style should be used throughout an application, it is better to configure the application's theme instead of styling every button individually.

MaterialApp(
  theme: ThemeData(
    elevatedButtonTheme: ElevatedButtonThemeData(
      style: ElevatedButton.styleFrom(
        backgroundColor: Colors.blue,
        foregroundColor: Colors.white,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(10),
        ),
      ),
    ),
  ),
  home: const HomePage(),
)

This approach helps maintain consistent button styling across the application.


22. Complete Example with All Three Buttons

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const ButtonDemo(),
    );
  }
}

class ButtonDemo extends StatelessWidget {
  const ButtonDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Buttons'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                print('ElevatedButton pressed');
              },
              child: const Text('Elevated Button'),
            ),
            const SizedBox(height: 15),
            TextButton(
              onPressed: () {
                print('TextButton pressed');
              },
              child: const Text('Text Button'),
            ),
            const SizedBox(height: 15),
            OutlinedButton(
              onPressed: () {
                print('OutlinedButton pressed');
              },
              child: const Text('Outlined Button'),
            ),
          ],
        ),
      ),
    );
  }
}

23. Practical Comparison Example

Column(
  crossAxisAlignment: CrossAxisAlignment.stretch,
  children: [
    ElevatedButton(
      onPressed: () {
        print('Primary action');
      },
      child: const Text('Submit Order'),
    ),
    const SizedBox(height: 10),
    OutlinedButton(
      onPressed: () {
        print('Secondary action');
      },
      child: const Text('Review Order'),
    ),
    const SizedBox(height: 10),
    TextButton(
      onPressed: () {
        print('Low priority action');
      },
      child: const Text('Cancel'),
    ),
  ],
)

In this example, the three buttons communicate different levels of visual emphasis.


24. Best Practices

  • Use ElevatedButton for important primary actions.
  • Use OutlinedButton for secondary actions that should still have a visible boundary.
  • Use TextButton for low-emphasis actions and inline actions.
  • Keep button labels short and action-oriented.
  • Use icons when they improve understanding of the action.
  • Maintain consistent button sizes throughout similar screens.
  • Use theme-level styling for application-wide consistency.
  • Make sure text has sufficient contrast against the button background.
  • Do not place too many visually prominent buttons next to each other.
  • Use disabled states when an action is temporarily unavailable.
  • Provide meaningful labels for accessibility.
  • Use appropriate spacing between adjacent buttons.

25. Common Mistakes

Mistake 1: Using Too Many Primary Buttons

Making every button an ElevatedButton can reduce the visual hierarchy of the interface.

Mistake 2: Very Long Button Labels

Keep button text concise and easy to understand.

Mistake 3: Poor Contrast

Make sure foreground and background colors provide sufficient readability.

Mistake 4: No Action Callback

ElevatedButton(
  child: const Text('Submit'),
)

The button requires an onPressed callback. Use onPressed: null when you intentionally want a disabled button.

Mistake 5: Inconsistent Styling

Using different button shapes, sizes, and colors randomly can make an application look inconsistent. Prefer a reusable design system or application theme.


26. Quick Selection Guide

Requirement Recommended Button
Primary action ElevatedButton
Secondary action with border OutlinedButton
Simple/low-emphasis action TextButton
Login ElevatedButton
Cancel in dialog TextButton
Register alternative OutlinedButton
Save ElevatedButton
View Details OutlinedButton or TextButton
Forgot Password TextButton

27. Interview Questions

  1. What is ElevatedButton in Flutter?
  2. What is the difference between ElevatedButton and TextButton?
  3. What is the difference between TextButton and OutlinedButton?
  4. How do you change the background color of an ElevatedButton?
  5. How do you change the border of an OutlinedButton?
  6. How do you create a button with an icon?
  7. How do you disable a Flutter button?
  8. What is ButtonStyle?
  9. What is the purpose of styleFrom()?
  10. How can you create a full-width button?
  11. How can you create rounded buttons?
  12. How can button styling be controlled globally?
  13. What are widget interaction states?
  14. How can a button change its style when pressed or hovered?
  15. What happens when onPressed is null?

28. Practice Exercises

  1. Create a login screen using ElevatedButton, TextButton, and OutlinedButton.
  2. Create a registration form with a primary Submit button and secondary Cancel button.
  3. Create a product page with Buy Now, Add to Cart, and View Details buttons.
  4. Create a dialog containing Cancel and Delete actions.
  5. Create a full-width ElevatedButton with rounded corners.
  6. Create an OutlinedButton with a custom border color and width.
  7. Create a TextButton with an icon.
  8. Create disabled buttons and enable them conditionally.
  9. Create a global ElevatedButton theme using ThemeData.
  10. Create state-dependent button colors for hover and pressed states.

29. Key Takeaways

  • ElevatedButton is suitable for prominent primary actions.
  • TextButton is suitable for low-emphasis and inline actions.
  • OutlinedButton is useful for secondary actions with a visible border.
  • The onPressed callback handles button interaction.
  • Setting onPressed to null disables the button.
  • styleFrom() provides a convenient way to customize button styles.
  • ButtonStyle provides detailed control over button appearance and states.
  • Buttons can contain both text and icons.
  • ThemeData can be used to create consistent application-wide button styles.
  • Good button hierarchy improves usability and makes interfaces easier to understand.

30. Learning Resources

For structured Flutter training, visit:

Official Flutter Documentation

whatsapp