image

14 Jan 2026

9K

35K

Creating an Expandable Card Widget for Product Descriptions in Flutter

In the dynamic world of e-commerce and mobile applications, presenting product information effectively is crucial. Product descriptions often need to be comprehensive, but displaying a large block of text upfront can overwhelm users and clutter the interface. A common and elegant solution to this challenge is to use an expandable card widget. This allows users to see a summary and then expand to view the full details only when they choose to, leading to a cleaner UI and improved user experience.

Why an Expandable Card?

  • Enhanced UI/UX: Keeps the initial screen clean and focused on essential information.
  • Efficient Space Usage: Maximizes screen real estate, especially on smaller mobile devices.
  • User Control: Gives users the power to decide how much information they want to consume.
  • Better Readability: Breaks down long texts into manageable, on-demand sections.

Core Concepts for Implementation

To build an expandable card in Flutter, we'll utilize a few key widgets and concepts:

  • StatefulWidget: Essential for managing the expanded/collapsed state of the card.
  • Card: Provides a visually distinct container for the product description.
  • Column: Used to stack the header (title and toggle icon) and the expandable content.
  • InkWell or GestureDetector: To detect taps on the card header and toggle its state.
  • AnimatedSize: Creates a smooth animation for the size change when the card expands or collapses.
  • Visibility: Conditionally renders the description text based on the expansion state.
  • AnimatedRotation: Adds a subtle rotation animation to the expansion icon for better visual feedback.

Building the Widget Step-by-Step

Let's walk through the process of creating our ExpandableProductDescriptionCard widget.

1. Basic Structure and State Management

We'll start with a StatefulWidget to hold the _isExpanded boolean state and a method to toggle it.

2. Header and Toggle Icon

The card's header will contain the title and an icon (e.g., a down arrow) that rotates to indicate the expansion state. We'll wrap this in an InkWell to make it tappable.

3. Expandable Content

The actual product description text will be placed inside a Visibility widget, which in turn is wrapped by AnimatedSize to animate its appearance and disappearance.

Full Code Example

Here's the complete code for our ExpandableProductDescriptionCard and an example of how to use it in a Flutter application.


import 'package:flutter/material.dart';

class ExpandableProductDescriptionCard extends StatefulWidget {
  final String title;
  final String description;

  const ExpandableProductDescriptionCard({
    Key? key,
    required this.title,
    required this.description,
  }) : super(key: key);

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

class _ExpandableProductDescriptionCardState
    extends State {
  bool _isExpanded = false;

  void _toggleExpanded() {
    setState(() {
      _isExpanded = !_isExpanded;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.all(16.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // Header Row: Contains title and toggle icon
          InkWell(
            onTap: _toggleExpanded,
            child: Padding(
              padding: const EdgeInsets.all(16.0),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Expanded(
                    child: Text(
                      widget.title,
                      style: const TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                  AnimatedRotation(
                    turns: _isExpanded ? 0.5 : 0.0, // Rotate 180 degrees
                    duration: const Duration(milliseconds: 300),
                    child: const Icon(Icons.keyboard_arrow_down),
                  ),
                ],
              ),
            ),
          ),
          // Expandable Content: Description text
          AnimatedSize(
            duration: const Duration(milliseconds: 300),
            curve: Curves.easeInOut,
            child: Visibility(
              visible: _isExpanded,
              // The key prevents issues when content changes rapidly if multiple such widgets exist
              key: ValueKey(_isExpanded),
              child: Padding(
                padding: const EdgeInsets.fromLTRB(16.0, 0, 16.0, 16.0),
                child: Text(
                  widget.description,
                  style: const TextStyle(fontSize: 16),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

// Example Usage in main.dart
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Expandable Card Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Product Details'),
        ),
        body: SingleChildScrollView(
          child: Column(
            children: [
              ExpandableProductDescriptionCard(
                title: 'Product Features',
                description:
                    'This is a comprehensive list of all the amazing features of our product. It includes high-quality materials, durable design, long-lasting battery life, and smart connectivity options. Enjoy seamless integration with your other devices and an intuitive user experience. The product also boasts a sleek, ergonomic design for maximum comfort and style. Ideal for both professional and casual use, it stands out with its innovative technology and robust performance.',
              ),
              ExpandableProductDescriptionCard(
                title: 'Technical Specifications',
                description:
                    'Weight: 250g, Dimensions: 10cm x 5cm x 2cm, Battery: 3000mAh Li-ion, Connectivity: Bluetooth 5.0, Wi-Fi 802.11ac, USB-C. Processor: Octa-core 2.5GHz, RAM: 8GB, Storage: 128GB. Display: 6.5-inch AMOLED, 1080p resolution. Operating System: Android 12.',
              ),
              ExpandableProductDescriptionCard(
                title: 'Customer Reviews',
                description:
                    'Our customers love this product! With an average rating of 4.8 stars, users praise its ease of use, robust performance, and stylish design. Many highlight the exceptional battery life and quick charging capabilities as major advantages. See what others are saying and join our growing community of satisfied users.',
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Code Explanation

  • ExpandableProductDescriptionCard: This is our StatefulWidget, taking title and description as required parameters.
  • _ExpandableProductDescriptionCardState: Manages the internal state.
    • _isExpanded: A boolean variable that determines if the description is currently visible.
    • _toggleExpanded(): A method called when the header is tapped. It flips the value of _isExpanded and calls setState() to rebuild the widget.
  • Card: Provides the material design card look and feel, with a default elevation and rounded corners.
  • InkWell: Wraps the header `Row` and makes it responsive to taps, providing a visual ripple effect.
  • Header Row: Contains the title of the card and an Icon.
    • Expanded(child: Text(...)): Ensures the title takes up available space, pushing the icon to the right.
    • AnimatedRotation: Rotates the Icons.keyboard_arrow_down icon by 180 degrees (0.5 turns) when _isExpanded is true, providing a smooth arrow-down/arrow-up animation.
  • AnimatedSize: This is crucial for the smooth animation. It wraps the Visibility widget and automatically animates its size change (height) when its child's size changes. It has a duration and curve for customizing the animation speed and style.
  • Visibility: Controls whether the Text widget containing the description is rendered. When visible is false, the widget is effectively removed from the render tree, allowing AnimatedSize to collapse. The ValueKey(_isExpanded) helps Flutter optimize widget tree updates.
  • Padding: Used to add appropriate spacing around the title and description for better aesthetics.

Conclusion

Creating an expandable card widget for product descriptions in Flutter is an effective way to enhance your application's user interface and experience. By combining Flutter's powerful layout widgets with state management and animation capabilities, you can build a highly functional and aesthetically pleasing component that efficiently presents information. This pattern is versatile and can be adapted for various other use cases where content needs to be revealed on demand.

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