Open In App

Flutter - Stepper Widget

Last Updated : 08 Jun, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

In this article, we will learn about the Stepper widget in Flutter. A stepper widget displays progress through a sequence of steps. A stepper is generally used in filling out forms online.

For example, remember filling out an online form for applying to any university or passport, or driving license. We filled the form step by step like

  • In step 1, we have filled in our details
  • In step 2, we have entered our residential address
  • In step 3, we have given  our education details
  • In step 4, we did the payment
  • In step 5, we got registered and printed the receipt

This is called a Stepper. Performing the task in a step-by-step process.

Now let's see the practical implementation of our stepper widget:

Step-by-Step Implementation

Step 1: Create a new Flutter Application

Create a new Flutter application using the command Prompt. To create a new app, write the following command and run it.

flutter create app_name

To know more about it refer this article: Creating a Simple Application in Flutter.

Step 2: Start Coding

In the scaffold, we initialized Stepper() and inside Stepper, we created a method called stepList(). This method was created because we have created a list of steps that are required in the form. 

Dart
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  
  // Here we have created list of steps that
  // are required to complete the form
   List<Step> stepList() => [
        const Step(title: Text('Account'), content: Center(child: Text('Account'),)),
         const Step(title: Text('Address'), content: Center(child: Text('Address'),)),
          const Step(title: Text('Confirm'), content: Center(child: Text('Confirm'),))
   ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        backgroundColor: Colors.green,
        title: const Text('GeeksforGeeks',style: TextStyle(color: Colors.white), ),
      ),
      
      // Here we have initialized the stepper widget 
      body: Stepper(
        steps: stepList(),
      )
    );
  }
}

Output:

Flutter---Stepper-Widget_vertical

Note: Now, this is the basic Stepper widget. If we want we can change the stepper in horizontal form as well. Just type the command in the below picture

 body: Stepper(
type: StepperType.horizontal,
steps: stepList(),
)

Output: 

Flutter---Stepper-Widget_horizontal


Step 3: Now let's add properties to this Stepper Widget like - 

  • currentStep: We have created an integer. Its initial value is 0. It shows the content of the step at which that particular index is.
  • onStepContinue:  It's the callback called when the continue button is tapped. When we click on the continue button, it takes us to the next step. If null, the ‘continue’ button will be disabled
  • onStepCancel: It's the callback called when the cancel button is tapped. When we click on the cancel button then we are pushed back to the previous step. If null, the ‘cancel’ button will be disabled.
  • onStepTapped: Callback called when the step is tapped. We can go directly to any step by just clicking on that particular step. For eg, if you want to go directly to step 2, then just click on it and you will be there.
Stepper(
type: StepperType.horizontal,
currentStep: _activeCurrentStep,
steps: stepList(),

// onStepContinue takes us to the next step
onStepContinue: () {
if (_activeCurrentStep < (stepList().length - 1)) {
setState(() {
_activeCurrentStep += 1;
});
}
},

// onStepCancel takes us to the previous step
onStepCancel: () {
if (_activeCurrentStep == 0) {
return;
}

setState(() {
_activeCurrentStep -= 1;
});
},

// onStepTap allows to directly click on the particular step we want
onStepTapped: (int index) {
setState(() {
_activeCurrentStep = index;
});
},
),

Step 4: In this step, we created a form by adding textfields so that the user can input data. So it looks more like a form-like structure.

  • In the first step, Account, we had added texfields - Full Name, Email, Password.
Flutter---Stepper-Widget_1


  • In the second step, Address, we had created a textfield - Full house Address, Pin Code.
Flutter---Stepper-Widget_2


  • In the third step, confirm that we are displaying data that the user has entered.
Flutter---Stepper-Widget_3


Complete Source Code

main.dart:

main.dart
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      debugShowCheckedModeBanner: false,
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // we have initialized active step to 0 so that
  // our stepper widget will start from first step
  int _activeCurrentStep = 0;

  TextEditingController name = TextEditingController();
  TextEditingController email = TextEditingController();
  TextEditingController pass = TextEditingController();
  TextEditingController address = TextEditingController();
  TextEditingController pincode = TextEditingController();

  // Here we have created list of steps
  // that are required to complete the form
  List<Step> stepList() => [
    // This is step1 which is called Account.
    // Here we will fill our personal details
    Step(
      state: _activeCurrentStep <= 0 ? StepState.editing : StepState.complete,
      isActive: _activeCurrentStep >= 0,
      title: const Text('Account'),
      content: Container(
        child: Column(
          children: [
            TextField(
              controller: name,
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Full Name',
              ),
            ),
            const SizedBox(height: 8),
            TextField(
              controller: email,
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Email',
              ),
            ),
            const SizedBox(height: 8),
            TextField(
              controller: pass,
              obscureText: true,
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Password',
              ),
            ),
          ],
        ),
      ),
    ),
    // This is Step2 here we will enter our address
    Step(
      state: _activeCurrentStep <= 1 ? StepState.editing : StepState.complete,
      isActive: _activeCurrentStep >= 1,
      title: const Text('Address'),
      content: Container(
        child: Column(
          children: [
            const SizedBox(height: 8),
            TextField(
              controller: address,
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Full House Address',
              ),
            ),
            const SizedBox(height: 8),
            TextField(
              controller: pincode,
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Pin Code',
              ),
            ),
          ],
        ),
      ),
    ),

    // This is Step3 here we will display all the details
    // that are entered by the user
    Step(
      state: StepState.complete,
      isActive: _activeCurrentStep >= 2,
      title: const Text('Confirm'),
      content: Container(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            Text('Name: ${name.text}'),
            Text('Email: ${email.text}'),
            Text('Password: ${pass.text}'),
            Text('Address : ${address.text}'),
            Text('PinCode : ${pincode.text}'),
          ],
        ),
      ),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.green,
        foregroundColor: Colors.white,
        title: const Text(
          'GeeksforGeeks',
        ),
      ),
      // Here we have initialized the stepper widget
      body: Stepper(
        type: StepperType.horizontal,
        currentStep: _activeCurrentStep,
        steps: stepList(),

        // onStepContinue takes us to the next step
        onStepContinue: () {
          if (_activeCurrentStep < (stepList().length - 1)) {
            setState(() {
              _activeCurrentStep += 1;
            });
          }
        },

        // onStepCancel takes us to the previous step
        onStepCancel: () {
          if (_activeCurrentStep == 0) {
            return;
          }

          setState(() {
            _activeCurrentStep -= 1;
          });
        },

        // onStepTap allows to directly click on the particular step we want
        onStepTapped: (int index) {
          setState(() {
            _activeCurrentStep = index;
          });
        },
      ),
    );
  }
}


Output: 

Explanation:

In this video, we can see that:

  • When we click on the continue button then we are heading towards the next step, which means our onStepContinue property is working.
  • When we click on the cancel button, we are getting back to the previous step, which means our onStepCancel property is working.
  • When we tap on a particular step, we get straight to that particular step, which means our onStepTapped property is working.

Next Article
Article Tags :

Similar Reads