multi_step_widgets 0.3.0+2 copy "multi_step_widgets: ^0.3.0+2" to clipboard
multi_step_widgets: ^0.3.0+2 copied to clipboard

Widgets for building multi-step flows, forms, and wizards

Multi-Step Widgets #

UI components for building multi-step flows, forms, and wizards in Flutter.

Benefits & Use Cases #

The multi_step_widgets package provides ready-to-use UI components that work seamlessly with the multi_step_flow architecture to create:

  • Engaging Onboarding Experiences: Create beautiful onboarding flows with animated transitions and interactive elements
  • Multi-Page Forms: Break complex forms into logical steps with validation and state persistence
  • Interactive Wizards: Guide users through complex setup processes with visual indicators of progress
  • Story-Based Content: Build interactive stories or educational content with automatic progression
  • Product Tours: Showcase features with step-by-step guidance
  • Multi-Stage Checkouts: Create intuitive e-commerce checkout experiences
  • Decision Trees: Implement conditional flows based on user responses

Features #

  • 🎯 Type-safe - Fully generic implementation with strong typing for compile-time safety
  • 🔄 BLoC integration - Clean architecture with predictable state management
  • 🎨 Customizable - Extensive theming and styling options for your brand identity
  • 📱 Responsive - Works on all platforms and screen sizes with adaptive layouts
  • 🧩 Specialized components - Form, information, and custom flows for various use cases

Installation #

dependencies:
  multi_step_widgets: ^0.3.0
  multi_step_flow: ^0.3.0  # Required dependency

Core Components #

FlowBuilder #

The core component for rendering multi-step flows:

FlowBuilder<UserData>(
  bloc: flowBloc,
  stepBuilder: (context, step) {
    // Build your step UI based on step.id
    return YourStepWidget(step: step);
  },
  // Optional customizations
  loadingBuilder: (context, state) => CircularProgressIndicator(),
  errorBuilder: (context, error) => Text('Error: $error'),
  completedBuilder: (context, state) => Text('Flow completed!'),
  transitionBuilder: (child, animation) {
    return FadeTransition(opacity: animation, child: child);
  },
  animateTransitions: true,
  transitionDuration: Duration(milliseconds: 300),
  onFlowCompleted: () => print('Flow completed!'),
)

FlowLayout #

A complete layout for multi-step flows:

FlowLayout<UserData>(
  bloc: flowBloc,
  stepBuilder: (context, step) => YourStepWidget(step: step),
  // Optional customizations
  indicatorBuilder: (state) => DotsIndicator<UserData>(bloc: flowBloc),
  showIndicator: true,
  showNavigationBar: true,
  navigationBarBuilder: (state) => FlowNavigationBar<UserData>(
    bloc: flowBloc, 
    nextLabel: Text('CONTINUE'),
    previousLabel: Text('BACK'),
  ),
  scrollDirection: FlowScrollDirection.horizontal,
  indicatorPosition: IndicatorPosition.top,
)
FlowNavigationBar<UserData>(
  bloc: flowBloc,
  showNextButton: true,
  showPreviousButton: true,
  showSkipButton: true,
  nextLabel: Text('NEXT'),
  previousLabel: Text('BACK'),
  skipLabel: Text('SKIP'),
  completeLabel: Text('FINISH'),
  // Button styles
  nextStyle: NavigationButtonStyle.filled,
  previousStyle: NavigationButtonStyle.outlined,
  skipStyle: NavigationButtonStyle.text,
)

Step Indicators #

DotsIndicator #

DotsIndicator<UserData>(
  bloc: flowBloc,
  axis: Axis.horizontal,
  mainAxisAlignment: MainAxisAlignment.center,
  theme: StepIndicatorThemeData(
    activeColor: Colors.blue,
    inactiveColor: Colors.grey,
    completedColor: Colors.green,
    errorColor: Colors.red,
    size: 8.0,
    spacing: 4.0,
    strokeWidth: 1.0,
  ),
  onStepTapped: (index) {
    // Navigate to step
    flowBloc.add(FlowEvent.stepSelected(index: index));
  },
)

Form Components #

FormStepBuilder #

Specialized component for form steps:

FormStepBuilder<UserData>(
  bloc: flowBloc,
  step: state.currentStep,
  formDataExtractor: (data) => data?.personalInfo ?? FormStepData(),
  formDataUpdater: (data, formData) {
    return data?.copyWith(personalInfo: formData) ?? 
           UserData(personalInfo: formData);
  },
  validators: {
    'name': (value) => (value == null || value.isEmpty) 
                    ? 'Name is required' : null,
    'email': (value) => !value.toString().contains('@') 
                    ? 'Invalid email' : null,
  },
  autovalidateMode: AutovalidateMode.onUserInteraction,
  builder: (context, formData, onChanged, formKey) {
    return FormStepLayout(
      title: 'Personal Information',
      description: 'Please enter your details',
      child: Column(
        children: [
          FlowFormField(
            fieldName: 'name',
            formData: formData,
            onChanged: onChanged,
            decoration: InputDecoration(labelText: 'Full Name'),
          ),
          SizedBox(height: 16),
          FlowFormField(
            fieldName: 'email',
            formData: formData,
            onChanged: onChanged,
            decoration: InputDecoration(labelText: 'Email Address'),
            keyboardType: TextInputType.emailAddress,
          ),
        ],
      ),
    );
  },
)

Information Components #

InformationStepBuilder #

For content-focused steps with read tracking:

InformationStepBuilder<TutorialData>(
  bloc: flowBloc,
  step: state.currentStep,
  infoDataExtractor: (data) => data?.introduction ?? InformationStepData(),
  infoDataUpdater: (data, infoData) {
    return data?.copyWith(introduction: infoData) ?? 
           TutorialData(introduction: infoData);
  },
  enableAutoReadTracking: true,
  showProgressIndicator: true,
  contentBuilder: (context, infoData, onUpdate) {
    return InformationStepLayout(
      title: 'Getting Started',
      description: 'Learn how to use our app',
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Image.asset('assets/tutorial1.png'),
          SizedBox(height: 16),
          Text(
            'Welcome to our application! This tutorial will help you...',
            style: Theme.of(context).textTheme.bodyLarge,
          ),
          // Content automatically tracks read progress
        ],
      ),
    );
  },
)

Theming and Customization #

FlowTheme #

FlowTheme(
  theme: FlowThemeData(
    indicatorTheme: StepIndicatorThemeData(
      activeColor: Colors.blue,
      inactiveColor: Colors.grey.shade300,
      completedColor: Colors.green,
      errorColor: Colors.red,
      size: 10.0,
      spacing: 4.0,
    ),
    navigationTheme: NavigationThemeData(
      primaryColor: Colors.blue,
      secondaryColor: Colors.grey,
      textStyle: TextStyle(fontWeight: FontWeight.bold),
      buttonPadding: EdgeInsets.symmetric(
        horizontal: 16.0, 
        vertical: 8.0
      ),
      buttonShape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(8.0),
      ),
    ),
  ),
  child: YourFlowWidget(),
)

Extending with Custom Components #

You can create custom indicators, navigation bars, or specialized step components:

// Custom step indicator
class NumberedIndicator<T> extends StepIndicator<T> {
  const NumberedIndicator({
    super.key,
    super.bloc,
    super.onStepTapped,
    super.theme,
  });

  @override
  Widget buildIndicator(BuildContext context, FlowState<T> state) {
    // Implementation for numbered steps
    return Row(children: [
      for (int i = 0; i < state.steps.length; i++)
        _buildNumberedStep(context, state, i),
    ]);
  }
  
  Widget _buildNumberedStep(BuildContext context, FlowState<T> state, int index) {
    final isActive = index == state.currentStepIndex;
    final isCompleted = state.validatedSteps.contains(state.steps[index].id);
    
    return GestureDetector(
      onTap: () => handleStepTap(context, state, index),
      child: Container(
        // Your custom UI implementation
      ),
    );
  }
}
``
1
likes
130
points
3
downloads

Publisher

unverified uploader

Weekly Downloads

Widgets for building multi-step flows, forms, and wizards

Homepage

Documentation

API reference

License

MIT (license)

Dependencies

flutter, flutter_bloc, multi_step_flow

More

Packages that depend on multi_step_widgets