How to use Flutter Radio buttons

Key takeaways:

  • The Radio widget supports a variety of parameters, such as value, groupValue, onChanged, activeColor, and fillColor, allowing fine-grained control over appearance and behavior.

  • By assigning the same groupValue to a group of Radio widgets, you can ensure mutual exclusivity, with dynamic state updates managed using setState and onChanged callbacks.

  • Add semanticLabel for screen readers and use FocusNode for keyboard navigation, ensuring inclusivity for users with disabilities.

  • Modify properties like splashRadius, visualDensity, and materialTapTargetSize to tailor the look and feel of the Radio widget. Combine with ListTile for cleaner layouts and better integration.

Radio buttons are widgets that allow users to select one option from a group of options. In Flutter, we can easily implement radio buttons using the Radio widget and a RadioListTile widget for a more convenient and user-friendly experience.

Constructor and parameters

The Radio widget provides a constructor with various parameters to customize its behavior and layout.

Radio({
  Key? key, 
  required T value, 
  required T? groupValue,
  required ValueChanged<T?>? onChanged,
  MouseCursor? mouseCursor, 
  bool toggleable = false, 
  Color? activeColor, 
  MaterialStateProperty<Color?>? fillColor,
  Color? focusColor, 
  Color? hoverColor, 
  MaterialStateProperty<Color?>? overlayColor,
  double? splashRadius, 
  MaterialTapTargetSize? materialTapTargetSize, 
  VisualDensity? visualDensity,
  FocusNode? focusNode,
  bool autofocus = false
})

Let's take a closer look at each parameter and its purpose:

  • key: An optional parameter representing the key to identify the Radio widget.

  • value: The value associated with the radio button. When the radio button is selected, this value is passed to the onChanged callback. The type T represents the data type of the value.

  • groupValue: The currently selected value in the group of radio buttons. The groupValue should match the value of the selected radio button. The type T represents the data type of the value.

  • onChanged: A callback function when the radio button is selected. It takes the newly selected value as its parameter, allowing us to handle the changes accordingly. The type T represents the data type of the value.

  • mouseCursor: An optional parameter specifying the mouse cursor to be used when the mouse hovers over the radio button.

  • toggleable: An optional parameter determining whether the radio button can be toggled on and off. If set to true, clicking the selected radio button will deselect it.

  • activeColor: An optional parameter that sets the radio button's color when selected.

  • fillColor: An optional parameter that defines the fill color of the radio button. The color can be customized based on different states, such as when it's pressed, hovered over, or disabled. We can use a MaterialStateColor to define different colors for different states.

  • focusColor: An optional parameter that sets the color of the radio button when it has keyboard focus.

  • hoverColor: An optional parameter that sets the color of the radio button when the mouse hovers over it.

  • overlayColor: An optional parameter that defines the color of the radio button's overlay when pressed. Similarly to fillColor, we can use a MaterialStateColor to customize the overlay color based on different states.

  • splashRadius: An optional parameter that determines the size of the splash radius when the radio button is pressed. It specifies the radius of the circular ripple effect around the button.

  • materialTapTargetSize: An optional parameter specifying the radio button's target size. It affects the hit test area of the button and can be used to adjust its overall size.

  • visualDensity: An optional parameter that allows us to adjust the spacing and density of the radio button within its surrounding container.

  • focusNode: An optional parameter that associates a FocusNode with the radio button. It enables keyboard focus management and navigation.

  • autofocus: An optional parameter determining whether the radio button should request focus when the widget is first displayed.

Accessibility considerations

Accessibility is crucial for ensuring that all users, including those with disabilities, can effectively use your app. In Flutter, we can make radio buttons accessible by setting the semanticLabel and ensuring that focus management is handled properly.

  1. semanticLabel: This optional parameter can be added to the Radio widget to provide a label for screen readers, ensuring that users with visual impairments understand the purpose of the radio button.

  2. Focus management: Ensure that the FocusNode is used to manage the focus on radio buttons when navigating with a keyboard. By enabling keyboard focus, users can interact with the radio buttons without needing to use a touchscreen.

Example:

Radio(
value: 1,
groupValue: selectedOption,
onChanged: (value) {
setState(() {
selectedOption = value;
});
},
semanticLabel: 'Option 1',
focusNode: FocusNode(),
autofocus: true, // Autofocus is optional, depending on the app's needs.
)

Adding a simple radio button

Import the necessary packages

To use the Radio widget, we need to import the flutter/material.dart package into your Dart file.

import 'package:flutter/material.dart';

Declaring variables

We need to declare selectedOption variable just above the build, which will hold the currently selected value of Radio widgets.

int selectedOption;

Sample code of the Flutter Radio button with a listTile:

import 'package:flutter/material.dart';  
  
void main() {  
  runApp(MaterialApp( home: MyHomePage(),));  
}  
  
class MyHomePage extends StatefulWidget {  
  @override  
  _HomePageState createState() => _HomePageState();  
}  
  
class _HomePageState extends State<MyHomePage> {  
  int selectedOption = 1; 
  
  @override  
  Widget build(BuildContext context) {  
    return MaterialApp(  
      home: Scaffold(  
        appBar: AppBar(title: Text('Educative Answers'),),  
        body: Container(  
            child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
              ListTile(
               title: const Text('www.educative.io'),
                leading: Radio<int>(
                  value: 1,
                  groupValue: selectedOption,
                  onChanged: (value) {
                   setState(() {
                    selectedOption = value;
                    print("Button value: $value");
                    });
                  },
                ),
              ),
            ],
          ),
        ),  
      ),  
    );  
  }  
}  
Addition of simple radio button

Code explanation

  1. Lines 21–38: Inside the Column, a ListTile widget is added, representing a single row in the list. It contains a Text widget as the title on line 5 and a Radio widget as the optional leading widget on line 6.

  2. Lines 26–35. The Radio widget is the radio button allowing a single option to select.

    1. Line 27: Here, we assigned 1 to its value property to make it distinguish between a group of radio buttons.

    2. Line 28: The groupValue property is set to the selectedOption variable, ensuring proper grouping of radio buttons.

    3. Line 29–34: The onChanged property is a callback function that triggers when the radio button is selected. Within this callback, setState() is called on to update the selectedOption variable with the newly selected value.

Let's see what output we get after executing:

Simple Radio button using ListTIle widget
Simple Radio button using ListTIle widget

Adding multiple radio buttons with a default value

Sample code of the Flutter for adding multiple Radio button with default value in a listTile:

import 'package:flutter/material.dart';  
  
void main() {  
  runApp(MaterialApp( home: MyHomePage(),));  
}  
  
class MyHomePage extends StatefulWidget {  
  @override  
  _HomePageState createState() => _HomePageState();  
}  
  
class _HomePageState extends State<MyHomePage> {  
  int selectedOption = 1; 
  
  @override  
  Widget build(BuildContext context) {  
    return MaterialApp(  
      home: Scaffold(  
        appBar: AppBar(title: Text('Educative Answers'),),  
        body: Container(  
            child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
              ListTile(
                title: const Text('Option 1'),
                leading: Radio<int>(
                  value: 1,
                  groupValue: selectedOption,
                  onChanged: (value) {
                    setState(() {
                      selectedOption = value;
                    });
                  },
                ),
              ),
              ListTile(
                title: const Text('Option 2'),
                leading: Radio<int>(
                  value: 2,
                  groupValue: selectedOption,
                  onChanged: (value) {
                    setState(() {
                      selectedOption = value;
                    });
                  },
                ),
              ),
            ],
          ),
        ),  
      ),  
    );  
  }  
}  
Addition of multiple radio buttons

To have the default selected radio button, we need to assign a value to selectedOption variable like this:

int selectedOption = 1;

Code explanation

  1. Lines 21–49: Inside, the Column are two ListTile widgets, representing two rows in the column.

  2. Line 25: The title property of the first ListTile is set to a Text widget with the text "Option 1".

  3. Line 26: The leading property of the first ListTile is set to a Radio widget. The Radio widget is a circular button representing a single option to select.

  4. Line 27: The value property of the first Radio widget is set to 1, indicating that it represents the first option.

  5. Line 28: The groupValue property of the first Radio widget is set to the selectedOption variable. This property is used to group radio buttons together.

  6. Lines 29–34: The onChanged property of the first Radio widget is set to a callback function. When the radio button is selected, this function will be called. It uses the setState method to update the selectedOption variable with the newly selected value.

  7. Lines 36–47: The second ListTile is similar to the first one, representing the second option.

Let's see what output we get after executing:

Radio buttons with default values
Radio buttons with default values

Change the radio button color

Sample code of the Flutter for adding color to the Radio button:

Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
ListTile(
title: const Text('Option 1'),
leading: Radio<int>(
value: 1,
groupValue: selectedOption,
activeColor: Colors.red, // Change the active radio button color here
fillColor: MaterialStateProperty.all(Colors.red), // Change the fill color when selected
splashRadius: 20, // Change the splash radius when clicked
onChanged: (int? value) {
setState(() {
selectedOption = value!;
});
},
),
),
ListTile(
title: const Text('Option 2'),
leading: Radio<int>(
value: 2,
groupValue: selectedOption,
activeColor: Colors.blue, // Change the active radio button color here
fillColor: MaterialStateProperty.all(Colors.blue), // Change the fill color when selected
splashRadius: 25, // Change the splash radius when clicked
onChanged: (int? value) {
setState(() {
selectedOption = value!;
});
},
),
),
],
),

Let's integrate that code and see how it turns out:

import 'package:flutter/material.dart';  
  
void main() {  
  runApp(MaterialApp( home: MyHomePage(),));  
}  
  
class MyHomePage extends StatefulWidget {  
  @override  
  _HomePageState createState() => _HomePageState();  
}  
  
class _HomePageState extends State<MyHomePage> {  
  int selectedOption = 1; 
  
  @override  
  Widget build(BuildContext context) {  
    return MaterialApp(  
      home: Scaffold(  
        appBar: AppBar(title: Text('Educative Answers'),),  
        body: Container(  
            child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
              ListTile(
                title: const Text('Option 1'),
                leading: Radio<int>(
                  value: 1,
                  groupValue: selectedOption,
                  activeColor: Colors.red, // Added activeColor
                  fillColor: MaterialStateProperty.all(Colors.red), // Added fillColor
                  splashRadius: 20, // Added splashRadius
                  onChanged: (value) {
                    setState(() {
                      selectedOption = value;
                      print("Button value: $value");
                    });
                  },
                ),
              ),
              ListTile(
                title: const Text('Option 2'),
                leading: Radio<int>(
                  value: 2,
                  groupValue: selectedOption,
                  activeColor: Colors.blue, // Added activeColor
                  fillColor: MaterialStateProperty.all(Colors.blue), // Added fillColor
                  splashRadius: 25, // Added splashRadius
                  onChanged: (value) {
                    setState(() {
                      selectedOption = value;
                    });
                  },
                ),
              ),
            ],
          ),
        ),  
      ),  
    );  
  }  
}  
Changing the button colors

Code explanation

This code is similar to the previous code explanation, with some additional properties set for the Radio widget.

  1. activeColor: This property sets the color of the selected radio button. In the first Radio widget, it is set to Colors.red, and in the second Radio widget, it is set to Colors.blue.

  2. fillColor: This property sets the color of the fill when the radio button is selected. It is set using the MaterialStateProperty.all constructor. Both Radio widgets are set to Colors.red and Colors.blue respectively.

  3. splashRadius: This property sets the radius of the splash effect when the radio button is clicked. In the first Radio widget, it is set to 20, and in the second Radio widget, it is set to 25.

  4. onChanged: This property defines the callback function when selecting the radio button. It updates the selectedOption variable.

Let's see what output we get after executing:

Customized radio buttons
Customized radio buttons

Complete code

We get the following output by putting together the code explained above.

import 'package:flutter/material.dart';  
  
void main() {  
  runApp(MaterialApp(home: MyHomePage()));  
}  
  
class MyHomePage extends StatefulWidget {  
  @override  
  _HomePageState createState() => _HomePageState();  
}  
  
class _HomePageState extends State<MyHomePage> {  
  int selectedOption = 1; 
  
  @override  
  Widget build(BuildContext context) {  
    return MaterialApp(  
      home: Scaffold(  
        appBar: AppBar(title: Text('Educative Answers')),  
        body: Container(  
          child: Column(  
            mainAxisAlignment: MainAxisAlignment.start,  
            children: <Widget>[  
              // Simple Radio Button
              ListTile(  
                title: const Text('www.educative.io'),  
                leading: Radio<int>(  
                  value: 1,  
                  groupValue: selectedOption,  
                  onChanged: (value) {  
                    setState(() {  
                      selectedOption = value;  // Removed null safety `!`
                      print("Button value: $value");  
                    });  
                  },  
                ),  
              ),  
              
              // Multiple Radio Buttons with default values
              ListTile(  
                title: const Text('Option 1'),  
                leading: Radio<int>(  
                  value: 1,  
                  groupValue: selectedOption,  
                  activeColor: Colors.red, // Added activeColor  
                  fillColor: MaterialStateProperty.all(Colors.red), // Added fillColor  
                  splashRadius: 20, // Added splashRadius  
                  onChanged: (value) {  
                    setState(() {  
                      selectedOption = value;  // Removed null safety `!`
                    });  
                  },  
                ),  
              ),  
              ListTile(  
                title: const Text('Option 2'),  
                leading: Radio<int>(  
                  value: 2,  
                  groupValue: selectedOption,  
                  activeColor: Colors.blue, // Added activeColor  
                  fillColor: MaterialStateProperty.all(Colors.blue), // Added fillColor  
                  splashRadius: 25, // Added splashRadius  
                  onChanged: (value) {  
                    setState(() {  
                      selectedOption = value;  // Removed null safety `!`
                    });  
                  },  
                ),  
              ),  
            ],  
          ),  
        ),  
      ),  
    );  
  }  
}
Complete implementation

Let's see what output we get after executing:

Complete layout
Complete layout

Testing radio buttons

When building apps, it's essential to test the functionality of the radio buttons to ensure correct behavior. We can write unit tests in Flutter using the flutter_test package to validate the radio button's selection logic.

Here’s a simple example of testing a radio button in Flutter:

testWidgets('Radio button selection test', (WidgetTester tester) async {
// Build the widget tree
await tester.pumpWidget(MyRadioApp());
// Verify that no option is selected initially
expect(find.byType(Radio), findsNWidgets(2));
// Tap the first radio button and trigger a frame
await tester.tap(find.byType(Radio).first);
await tester.pump();
// Verify that the first option is now selected
expect(find.text('Option 1'), findsOneWidget);
});

Conclusion

Flutter provides a simple and effective way to implement radio buttons. We can create visually appealing and interactive user options with the Radio widget and its customizable properties. We can easily handle the selection changes and update the UI by utilizing the callback. With Flutter's radio buttons, we can enhance our app's user experience and create intuitive interfaces.

Further learning

  • Learn how to implement other selection widgets like checkboxes and switches, which provide alternative ways for users to select options in a form or UI.

  • Explore creating custom widgets in Flutter to design reusable, more complex UI components that can be tailored specifically to your app’s requirements.

  • Study how to work with forms, including input fields and validation logic, ensuring user data is correctly formatted and validated before submission.

Ready to build stunning Android apps? Beginning Flutter: Android Mobile App Development takes you from designing contact profiles to integrating APIs and publishing your app, all with Flutter's powerful UI framework.

Frequently asked questions

Haven’t found what you were looking for? Contact Us


How to use RadioListTile Flutter?

To use RadioListTile in Flutter:

  • Declare a variable to track the currently selected value from the available options.

  • The RadioListTile widget combines a radio button with a list tile, making it easy to display both a label and the radio button.

  • Set the value and groupValue properties to manage which option is selected.

  • Use the onChanged callback to update the selected value when a user selects an option.

This creates a user-friendly, clickable list tile with a built-in radio button.


What is groupValue in radio button Flutter?

The groupValue in a Flutter radio button is used to manage the selection among multiple radio buttons in a group. It represents the currently selected value of the group.

  • Each radio button in the group has a value property, and if the groupValue matches the value of a radio button, that radio button will be selected.

  • The groupValue helps to ensure that only one radio button in the group is selected at any time.

In summary, groupValue controls which radio button in the group is currently active or selected.


How do you toggle radio buttons in Flutter?

To toggle radio buttons in Flutter:

  • By default, radio buttons in Flutter are not toggleable, meaning once a radio button is selected, it cannot be deselected by clicking it again.

  • However, you can enable toggling by setting the toggleable property of the Radio widget to true.

  • When toggleable is set to true, clicking an already selected radio button will deselect it, making all options unselected.

This behavior allows users to deselect a previously chosen radio button option when needed.


Free Resources

Copyright ©2025 Educative, Inc. All rights reserved