image

09 Jan 2026

9K

35K

Building a Profile Summary Card Widget in Flutter

Profile summary cards are a ubiquitous UI element in modern applications, providing a concise overview of a user's identity and key statistics. They are essential for social apps, e-commerce platforms, or any application where user profiles are a central feature. In Flutter, creating such a widget is straightforward, leveraging the powerful composition model and rich set of pre-built widgets. This article will guide you through building a customizable profile summary card using Flutter.

Understanding the Core Components

A typical profile summary card includes several key components:

  • Avatar/Profile Picture: A circular image representing the user.
  • User Name: The user's full name or username.
  • Title/Bio: A short description of the user's role, profession, or a brief bio.
  • Statistics: Numbers like posts, followers, following, etc.
  • Action Buttons (Optional): Buttons for actions like "Follow," "Message," or "Edit Profile."

We'll combine these elements using Flutter's layout widgets like Column, Row, and Card, and apply styling with TextStyle and BoxDecoration.

Setting Up the Basic Card Structure

We'll start by creating a StatelessWidget named ProfileSummaryCard. This widget will encapsulate all the UI logic for our card. We'll use a Card widget for its elevated and rounded appearance, and a Column to arrange our elements vertically.


import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.all(16.0),
      elevation: 4.0,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(12.0),
      ),
      child: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          mainAxisSize: MainAxisSize.min, // Ensures column takes minimum space
          children: [
            // Avatar will go here
            // User information will go here
            // Optional stats/actions will go here
          ],
        ),
      ),
    );
  }
}

In this initial structure:

  • Card provides the elevated container with rounded corners.
  • margin adds space around the card.
  • Padding creates inner spacing for the content.
  • Column is used for vertical arrangement of widgets.
  • mainAxisSize.min ensures the column only takes up as much vertical space as its children need, making the card compact.

Adding the Profile Avatar

The profile avatar is a central visual element. We'll use CircleAvatar, which conveniently handles circular clipping and can display network images.


// Inside the Column's children in ProfileSummaryCard's build method
CircleAvatar(
  radius: 40.0,
  backgroundImage: NetworkImage('https://example.com/profile_pic.jpg'), // Replace with actual image URL
  backgroundColor: Colors.grey.shade200, // Placeholder background color
),

Displaying User Information

Below the avatar, we'll place the user's name and title/bio. These will also be arranged vertically using a Column (or simply placed directly in the main Column for simplicity, using Text widgets).


// Below the CircleAvatar, inside the Column's children
const SizedBox(height: 12.0), // Spacing below avatar
Text(
  'John Doe',
  style: TextStyle(
    fontSize: 22.0,
    fontWeight: FontWeight.bold,
  ),
),
const SizedBox(height: 4.0), // Spacing between name and title
Text(
  'Software Engineer | Flutter Developer',
  textAlign: TextAlign.center,
  style: TextStyle(
    fontSize: 16.0,
    color: Colors.grey.shade600,
  ),
),

Integrating Optional Statistics and Actions

To display statistics like posts, followers, and following, we can use a Row widget. For an action button like "Follow," an ElevatedButton is suitable. We'll also create a helper method to build the individual stat columns for reusability.


// Helper method within the ProfileSummaryCard class
Widget _buildStatColumn(String label, String value) {
  return Column(
    children: [
      Text(
        value,
        style: const TextStyle(
          fontSize: 18.0,
          fontWeight: FontWeight.bold,
        ),
      ),
      const SizedBox(height: 4.0),
      Text(
        label,
        style: TextStyle(
          fontSize: 14.0,
          color: Colors.grey.shade600,
        ),
      ),
    ],
  );
}

// Below user information, inside the Column's children
const SizedBox(height: 16.0), // Spacing above stats
Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [
    _buildStatColumn('Posts', '120'),
    _buildStatColumn('Followers', '2.5K'),
    _buildStatColumn('Following', '300'),
  ],
),
const SizedBox(height: 16.0), // Spacing above button
SizedBox( // Use SizedBox to control button width
  width: double.infinity, // Make button take full width
  child: ElevatedButton(
    onPressed: () {
      // Handle follow action
      print('Follow button pressed!');
    },
    style: ElevatedButton.styleFrom(
      backgroundColor: Colors.blueAccent,
      foregroundColor: Colors.white,
      padding: const EdgeInsets.symmetric(vertical: 12),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(8.0),
      ),
    ),
    child: const Text(
      'Follow',
      style: TextStyle(fontSize: 16.0),
    ),
  ),
),

Making the Widget Reusable and Dynamic

To make our ProfileSummaryCard truly useful, we need to pass data dynamically. We'll add properties to the widget constructor.


import 'package:flutter/material.dart';

class ProfileSummaryCard extends StatelessWidget {
  final String imageUrl;
  final String name;
  final String title;
  final int posts;
  final String followers;
  final int following;
  final VoidCallback? onFollowPressed;

  const ProfileSummaryCard({
    super.key,
    required this.imageUrl,
    required this.name,
    required this.title,
    this.posts = 0,
    this.followers = '0',
    this.following = 0,
    this.onFollowPressed,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.all(16.0),
      elevation: 4.0,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(12.0),
      ),
      child: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            CircleAvatar(
              radius: 40.0,
              backgroundImage: NetworkImage(imageUrl),
              backgroundColor: Colors.grey.shade200,
            ),
            const SizedBox(height: 12.0),
            Text(
              name,
              style: const TextStyle(
                fontSize: 22.0,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 4.0),
            Text(
              title,
              textAlign: TextAlign.center,
              style: TextStyle(
                fontSize: 16.0,
                color: Colors.grey.shade600,
              ),
            ),
            const SizedBox(height: 16.0),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                _buildStatColumn('Posts', posts.toString()),
                _buildStatColumn('Followers', followers),
                _buildStatColumn('Following', following.toString()),
              ],
            ),
            if (onFollowPressed != null) ...[
              const SizedBox(height: 16.0),
              SizedBox(
                width: double.infinity,
                child: ElevatedButton(
                  onPressed: onFollowPressed,
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.blueAccent,
                    foregroundColor: Colors.white,
                    padding: const EdgeInsets.symmetric(vertical: 12),
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(8.0),
                    ),
                  ),
                  child: const Text(
                    'Follow',
                    style: TextStyle(fontSize: 16.0),
                  ),
                ),
              ),
            ],
          ],
        ),
      ),
    );
  }

  Widget _buildStatColumn(String label, String value) {
    return Column(
      children: [
        Text(
          value,
          style: const TextStyle(
            fontSize: 18.0,
            fontWeight: FontWeight.bold,
          ),
        ),
        const SizedBox(height: 4.0),
        Text(
          label,
          style: TextStyle(
            fontSize: 14.0,
            color: Colors.grey.shade600,
          ),
        ),
      ],
    );
  }
}

Using the Profile Summary Card

Now that our ProfileSummaryCard is complete and dynamic, you can easily integrate it into any Flutter screen. Create a new file (e.g., profile_summary_card.dart) for the widget and import it where needed.


import 'package:flutter/material.dart';
import 'profile_summary_card.dart'; // Make sure this path is correct for your project

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Profile Card Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Profile Summary'),
      ),
      body: Center(
        child: ProfileSummaryCard(
          imageUrl: 'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png',
          name: 'Jane Doe',
          title: 'UX Designer | Creative Lead at Tech Solutions',
          posts: 150,
          followers: '10K',
          following: 500,
          onFollowPressed: () {
            // Implement actual follow logic here
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(content: Text('Follow button clicked!')),
            );
          },
        ),
      ),
    );
  }
}

Conclusion

Building a profile summary card in Flutter is an excellent way to practice widget composition, styling, and making reusable components. By breaking down the UI into smaller, manageable widgets and using constructor parameters, you can create flexible and powerful UI elements for your applications. This example provides a solid foundation, which you can further enhance with animations, more complex layouts, or integration with backend data.

Related Articles

May 14, 2026

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter Countdown timers are essential in many applic

May 11, 2026

Unleashing Dynamic UIs: Flutter's Animation Prowess

Unleashing Dynamic UIs: Flutter's Animation Prowess for Slide & Scale Effects Flutter's declarative UI framework, combined with its powerful animation capabilit

May 11, 2026

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy A well-designed Product Detail Page (PDP) is