expandable_plus 1.1.1
expandable_plus: ^1.1.1 copied to clipboard
Expandable and collapsible panels with accordion groups for Flutter. A maintained, drop-in successor to the expandable package; adds header padding, fixes body-tap toggling.
expandable_plus #

A maintained continuation of the expandable package. It shows content that the
user can expand or collapse, with an optional header, an animated icon, and a
cross-fade between the collapsed and expanded views.
expandable has not had a release since 2021 and has a backlog of open issues.
expandable_plus keeps the same public API. Moving to it costs one import
line, and it closes some of the most requested gaps. It adds
accordion groups and a header padding option, and it fixes body taps on a
standalone panel.
Migration from expandable #
Change the import, and your existing panels behave the same.
// before
import 'package:expandable/expandable.dart';
// after
import 'package:expandable_plus/expandable_plus.dart';
The class names, fields, and defaults are the same. Your existing panels look and behave the way they did.
Install #
flutter pub add expandable_plus
Usage #
A basic panel #
ExpandablePanel(
header: const Text('Details'),
collapsed: const Text(
'A short summary.',
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
expanded: const Text('The full text goes here.'),
)
An accordion group #
Pass one ExpandableGroupController to several panels. When one opens, the
others close. Panels that are not in a group are unaffected.
final group = ExpandableGroupController();
Column(
children: [
ExpandablePanel(
controller: ExpandableController(group: group),
header: const Text('Section 1'),
collapsed: const Text('Summary 1'),
expanded: const Text('Body 1'),
),
ExpandablePanel(
controller: ExpandableController(group: group),
header: const Text('Section 2'),
collapsed: const Text('Summary 2'),
expanded: const Text('Body 2'),
),
],
)
Pass ExpandableGroupController(allowAllCollapsed: false) to keep one section
open at all times. Dispose the group when you are done with it, for example in
your State.dispose.
Header padding #
headerPadding controls the space around the header. The default is
EdgeInsets.zero, which matches expandable.
ExpandablePanel(
theme: const ExpandableThemeData(headerPadding: EdgeInsets.all(16)),
header: const Text('Details'),
collapsed: const Text('Summary'),
expanded: const Text('Body'),
)
Long lists: lazy #
A cross-fade keeps both children in the tree, and a collapsed panel still builds
its expanded body. One panel never notices. Twenty do: put twenty collapsed
ExpandablePanels in a ListView and fifteen expanded bodies are built on the
first frame, one for every panel the viewport lays out. Measured in
test/lazy_test.dart, which pins the number.
lazy: true holds a panel's body back until it first opens:
ExpandablePanel(
lazy: true,
header: const Text('Section'),
collapsed: const Text('Summary'),
expanded: const HeavyBody(),
)
The first expand swaps the real child in, and it stays. Closing and reopening
costs nothing and keeps whatever state the body was holding, because its
initState runs once.
Off by default. Turning it on moves when a child's initState runs. That
matters if the body has to be alive before anyone opens it, which makes this a
decision rather than a default. Panels built through builder place both
children themselves and are unaffected.
Accessibility #
The header is a real button to a screen reader, and it carries the panel's
open state. A user hears "collapsed" or "expanded", and hears it change when
they press it. That comes from ExpandableButton, which every header and
header icon goes through. Panels and accordion groups get it without any
setup:
ExpandablePanel(
header: Text('Details'), // announced as a button, expanded or collapsed
collapsed: Text('Summary'),
expanded: Text('Everything'),
)
Nothing needs to be passed for this. It tracks the controller, and expanding a panel from code updates the announcement too.
What's fixed #
- Open one panel at a time: #8
- Remove the padding around the header: #72
tapBodyToExpandandtapBodyToCollapsenot working: #50- Example not compiling: #114
- No screen-reader support: the header exposed no button role and no expanded state, leaving the control unusable with assistive technology
Credits #
Based on expandable by Alexander Ryzhov (MIT). Original repository:
https://github.com/aryzhov/flutter-expandable
License #
MIT. See LICENSE.