Exploring Simple Widgets I: The Expansion Tile
Tags: flutter, mobile, coding, dart
Published: 2023-08-06 22:18:07

## What is the Expansion Tile Widget?

The Expansion Tile Widget is a part of the Flutter material library that allows developers to create a collapsible tile with two states: **expanded** and **collapsed**. It is widely used to create lists with items that can expand or collapse to reveal more content. This widget is particularly useful when dealing with limited screen space and the need to display additional information when required. 

## How does it work?
The Expansion Tile Widget consists of a header and a body. When the user taps on the header, the widget expands, revealing the content inside the body. Subsequently, another tap collapses the widget, hiding the content. Think of things like FAQ section where the answer to a question is revealed when  the question tile is clicked on or a Post that reveals more info (or a comment section) when clicked.

## How to use the Expansion Tile
To use the Expansion Tile Widget, simply add it to the body of your scaffold. It has a single required _title_ parameter which takes a widget (so it could be literally any widget). It shows the title of the Expansion tile.

```
class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Expansion Tile'),
      ),
      body: Center(
        // our Expansion Tile here
        child: ExpansionTile(
          title: Text('Hey, I can Expand'),
         
        ),
      ) );
  }
}

```

![Collapsed State](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q37gqhaoepcvsnkewbv1.png)


![Expanded State but Empty](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2az5graopoydplns8h8e.png)

Although we can see the change when we click on the tile, it doesn't exactly expand. That's because we haven't added the hidden items.

To add the hidden items to be revealed, we have a _children_ property that takes in a List of widgets.

```
 ExpansionTile(
          title: Text('Hey, I Expand'),
          //adding the hidden items
          children: [
            ListTile(
              title: Text('Can you see me? I am a ListTile'),
              trailing: Icon(Icons.waving_hand)
            ),
             SizedBox(height: 10,),
            Text('I am a boring Text'),
            SizedBox(height: 10,),
            CircleAvatar(
              radius: 25,
              child: CircleAvatar(
                radius: 20,
                backgroundColor: Colors.white,
                child: FlutterLogo()),
            )
          ],
        ),
```

![Expanded state with Children](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4pfmi5nfihzz5ao2bwo7.png)

Well, that's basically all you need to do to use the ExpansionTile widget. But there are other fun stuff to play around with.
As you can see, there's a default expand more(arrow down) and expand less(arrow down) icon when we expand and collapse the tile, we can use our preferred Icon(or widget) using the _trailing_ parameter or nothing at all by just setting the value to a SizedBox. 
There's also an _onExpansionChanged_ parameter which takes a function with a boolean param that basically tells us the state of the tile and we can do something in this function when we change the state of the tile.

```
class Home extends StatefulWidget {
  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  bool isExpanded = false;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Expansion Tile'),
      ),
      body: Center(
        child: ExpansionTile(
          title: Text('Hey, I Expand'),
          trailing: Text(isExpanded ? 'close' : 'open'),
          //adding the hidden items
          onExpansionChanged: (val){
            setState((){
              isExpanded = val;
            });
          },
          children: [
            ListTile(
              title: Text('Can you see me? I am a ListTile'),
              trailing: Icon(Icons.waving_hand)
            ),
             SizedBox(height: 10,),
            Text('I am a boring Text'),
            SizedBox(height: 10,),
            CircleAvatar(
              radius: 25,
              child: CircleAvatar(
                radius: 20,
                backgroundColor: Colors.white,
                child: FlutterLogo()),
            )
          ],
        ),
      ) );
  }
}
```


![Collapsed tile with custom trailing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/en7tpg7x7j8wa9rax0jh.png)

![Expanded tile with custom trailing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cg5vn7qpvvu2d7zdaob5.png)

In the snippet above, we changed our _Home_ to a stateful widget so we could update our trailer from open to closed using setState((){}) when the tile changes.

There are other interesting attributes in the Expansion tile which includes boolean values _intiallyExpanded_ for specifying the initial state of the tile and _maintainState_ to specify whether the children widget be kept in the widget tree or recreated each time the tile is Expanded.
There is also the _tilePadding_ for specifying the padding of the Expansion tile and _childrenPadding_ for the children's padding.
Other values are provided are for styling our ExpansionTile includes such as the colors and shapes.

Here's a full list of all its Attributes:
```
(new) ExpansionTile ExpansionTile({
  Key? key,
  Widget? leading,
  required Widget title,
  Widget? subtitle,
  void Function(bool)? onExpansionChanged,
  List<Widget> children = const <Widget>[],
  Widget? trailing,
  bool initiallyExpanded = false,
  bool maintainState = false,
  EdgeInsetsGeometry? tilePadding,
  CrossAxisAlignment? expandedCrossAxisAlignment,
  Alignment? expandedAlignment,
  EdgeInsetsGeometry? childrenPadding,
  Color? backgroundColor,
  Color? collapsedBackgroundColor,
  Color? textColor,
  Color? collapsedTextColor,
  Color? iconColor,
  Color? collapsedIconColor,
  ShapeBorder? shape,
  ShapeBorder? collapsedShape,
  Clip? clipBehavior,
  ListTileControlAffinity? controlAffinity,
})
```

## Nesting Expansion Tiles

A common question that comes to mind is whether we can nest multiple expansion tiles in each other.Yes we can! However, while this is possible, it is advisable to limit the depth of the nesting to avoid overwhelming the user and to maintain a clear interface. 

```
class Home extends StatefulWidget {
  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  bool isExpanded = false;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Expansion Tile'),
      ),
      body: Center(
        child: Column(
          children: [
            ExpansionTile(
              controlAffinity: ListTileControlAffinity.trailing,
              title: Text('Hey, I Expand'),
              initiallyExpanded: true,
              maintainState: true,
              subtitle: Text('Click me'),
              trailing: Text(isExpanded ? 'close' : 'open'),
              //adding the hidden items
              onExpansionChanged: (val){
                setState((){
                  isExpanded = val;
                });
              },
              children: [
                ListTile(
                  title: Text('Can you see me? I am a ListTile'),
                  trailing: Icon(Icons.waving_hand)
                ),
                 SizedBox(height: 10,),
                Text('I am a boring Text'),
                SizedBox(height: 10,),
                CircleAvatar(
                  radius: 25,
                  child: CircleAvatar(
                    radius: 20,
                    backgroundColor: Colors.white,
                    child: FlutterLogo()),
                )
              ],
            ),
            ExpansionTile(
  title: Text('Parent Tile'),
  children: [
    ExpansionTile(
      title: Text('Child Tile 1'),
      children: [
        ListTile(
          title: Text('Content 1'),
        ),
      ],
    ),
    ExpansionTile(
      title: Text('Child Tile 2'),
      children: [
        ListTile(
          title: Text('Content 2'),
        ),
      ],
    ),
  ],
)
          ],
        ),
      ) );
  }
}

```

![Multiple Expansion Tiles](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pyu85efl39ek3zikxu2b.png)

![Nested Expansion Tile depth 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lz8td7fr5h0e0hqdypv9.png)

![Nested Expansion Tile depth 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9xhatbozqboivo990tzz.png)

##  Conclusion

The Expansion Tile Widget in Flutter provides developers with a powerful tool to create collapsible and expandable content areas, enhancing user experience and improving UI design. By customizing the widget's appearance and behaviour, developers can create intuitive and engaging interfaces for their Flutter applications.

Checkout an interesting use of Expansion Tile in the GitHub gist below: 
[Github Gist](https://gist.github.com/HassanTeslim007/f5add1d59c55d1bb5159dc8e591c399d)

Please suggest in the comment what Widget I should look into next. Thank you