flutter_sliding_comment_sheet
A comment sheet that slides up and shrinks the content above it instead of covering it — the pattern TikTok, Instagram Reels and YouTube Shorts all use.
Opening the comments scales the video down rather than covering it. Pulling the comment list down at its top hands the drag to the sheet, and letting go part way springs it back — one gesture, no lifting your finger.
showModalBottomSheet and DraggableScrollableSheet draw over the page. For
a video feed that is the wrong behaviour: the video stays full size behind the
sheet and its bottom half disappears. This widget takes the space away from the
content instead, so the video shrinks into the room left above the sheet and
stays fully visible while the comments are open.
The sheet's contents are yours. This package owns the motion, not the comment UI.
Usage
final sheet = SlidingCommentSheetController();
Scaffold(
// The sheet lifts itself above the keyboard, so the scaffold must not
// shrink the page for it as well.
resizeToAvoidBottomInset: false,
body: SlidingCommentSheet(
controller: sheet,
maxSheetHeight: 400,
content: VideoPlayer(videoController), // shrinks when the sheet opens
sheetBuilder: (context, scrollController) => ListView.builder(
controller: scrollController, // see below — this matters
itemCount: comments.length,
itemBuilder: (context, i) => CommentTile(comments[i]),
),
),
)
Attach the scroll controller
sheetBuilder hands you a ScrollController. Give it to whatever scrolls
inside the sheet.
That is what makes the gesture behave the way it does in the apps this imitates: pull down on the comment list when it is at the top and the sheet closes; push up and the sheet opens before the list starts scrolling — all in one unbroken gesture, without lifting your finger.
Skip it and the list keeps the whole gesture to itself, leaving the sheet draggable only by whatever non-scrolling chrome it has. A sheet with nothing to scroll can ignore the argument.
Open and close it from anywhere:
IconButton(
icon: const Icon(Icons.comment),
onPressed: sheet.toggle,
)
Dispose the controller when you are done with it.
What you get
- The content resizes rather than being covered
- Pull down on the comment list itself to close the sheet
- Drag or flick the sheet down to close it, with the throw's momentum carried into the settle
- Back button closes the sheet before it leaves the page
- Tap the content to dismiss
- Lifts above the keyboard
- Follows the finger exactly — no jump-to-touch
- Sheet contents translate instead of reflowing, so a header or input row inside it never overflows mid-animation
- Optional rounded corners on the content, growing with the sheet
- Haptics on settle, a screen-reader label and a dismiss action
- No dependencies beyond Flutter, and no state management library
The controller
SlidingCommentSheetController opens and closes the sheet from anywhere, and
follows it as it moves.
| Member | |
|---|---|
expand() |
Animate the sheet open |
collapse() |
Animate it shut |
toggle() |
Whichever way it currently is |
isExpanded |
True past the halfway point |
progress |
0 when closed, 1 when fully open, updated every frame |
isAttached |
Whether a sheet is currently built and listening |
dispose() |
Yours to call — the sheet does not own the controller |
It is also a ChangeNotifier that fires every frame, so you can follow the
sheet as it moves:
ListenableBuilder(
listenable: sheet,
builder: (context, _) => Opacity(
opacity: 1 - sheet.progress, // fade the overlay out as it opens
child: const VideoActions(),
),
)
progress runs from 0 when closed to 1 when fully open. isExpanded is true
past the halfway point.
Options
| Parameter | Default | |
|---|---|---|
content |
required | The page behind the sheet, which shrinks |
sheetBuilder |
required | Builds the sheet, given a ScrollController |
controller |
null |
Opens and closes it from outside |
maxSheetHeight |
60% of height | Height when fully open |
minSheetHeight |
0 |
Height when closed; set it to leave the sheet peeking |
dismissThreshold |
0.4 |
How far open the sheet must still be on release to spring back rather than close |
flingVelocity |
700 |
Speed, in px/s, at which a flick wins over position |
duration |
250ms |
Time for a controller-driven move, scaled by distance |
curve |
Curves.easeOut |
Applies to controller-driven moves, not to a released drag |
backgroundColor |
null |
Painted behind the content |
contentBorderRadius |
null |
Rounds the content's corners as the sheet opens |
onExpand / onCollapse |
null |
Fired once per transition |
enableDrag |
true |
|
barrierDismissible |
true |
Tap the content to close. The barrier sits over the content, so it also stops it being poked at while the sheet is open |
keyboardAware |
true |
Lift above the keyboard |
initiallyExpanded |
false |
Start open, for a page opened onto the comments |
enableFeedback |
true |
A haptic tick when the sheet settles open or shut |
semanticLabel |
null |
What a screen reader calls the sheet |
Notes
The sheet is built only while it is open, so scroll position and any state inside it reset when it closes — keep anything you want to survive, like a half-typed comment, in a controller you own.
Keyboard
The sheet lifts itself using MediaQuery.viewInsetsOf. Set
resizeToAvoidBottomInset: false on the surrounding Scaffold, otherwise the
scaffold shrinks the whole page for the keyboard and the sheet lifts twice. Turn
keyboardAware off if you would rather handle it yourself.
Example
example/ is a working short-video feed: streaming video, a swipeable vertical
PageView, an action rail, and a comment sheet per clip. Run it with
cd example && flutter run.
Open the comments and watch the video scale down into the space left above the sheet, then pull down on the comment list itself to close it.
It also has an on-device gesture suite:
cd example && flutter test integration_test/gesture_test.dart
License
BSD 3-Clause. See LICENSE.
Libraries
- flutter_sliding_comment_sheet
- A comment sheet that slides up and shrinks the content above it, as seen in TikTok, Instagram Reels and YouTube Shorts.