elastic_sheet 0.2.0
elastic_sheet: ^0.2.0 copied to clipboard
A physics-driven Flutter surface for anchor-based expansion, liquid spring motion, dynamic sizing, and partial actions.
Elastic Sheet #
A physics-driven Flutter surface that expands from its own anchor with liquid spring motion. Build compact buttons, floating action panels, composer bars, filters, checkout sections, and adaptive surfaces that grow in-place instead of opening as disconnected modals.
Open Live Demo · Example Source · pub.flutter-io.cn
Live Demo #
Try the interactive Elastic Sheet Playground directly in your browser:
The demo is powered by the same Flutter example app under:
example/lib/src/elastic_sheet_playground.dart
It lets you tune stiffness, damping, mass, overshoot, durations, rebound profile, anchors, placement, and collapsed/expanded sizes while seeing the result instantly.
Showcase #
| Feature | Description | Preview |
|---|---|---|
| Spring Presets | Switch between tuned motion profiles from gentle to snappy. | ![]() |
| Anchor (Compact) | Expand naturally from corners, edges, or center without disrupting the surrounding UI. | ![]() |
| Anchor (Grid) | Keep complex layouts visually stable while surfaces grow from their original position. | ![]() |
Features #
- Expand from any of 9 anchors: corners, edges, or center.
- Spring-based motion with configurable stiffness, damping, mass, and overshoot.
- Built-in motion presets: gentle, bouncy, natural, and snappy.
- Fixed or dynamic expanded sizing.
- Declarative
isExpandedAPI. - Controller-based API through
ElasticSheetController. - Partial child actions through
ElasticSheetActions. - Content states for ready, pending, and unavailable surfaces.
- Production-style example app and browser playground.
Installation #
dependencies:
elastic_sheet: ^0.2.0
Usage #
ElasticSheet(
isExpanded: isExpanded,
anchor: ElasticSheetAnchor.bottomCenter,
config: const ElasticSheetConfig.natural(),
collapsedSize: const Size(220, 52),
expandedSize: const Size(320, 280),
collapsedChild: const Center(child: Text('Open')),
expandedChild: const Padding(
padding: EdgeInsets.all(20),
child: Text('Expanded content'),
),
)
Controller API #
Use ElasticSheetController when the surface should be opened, closed, toggled, or pulsed from outside the widget.
late final ElasticSheetController controller;
@override
void initState() {
super.initState();
controller = ElasticSheetController(
vsync: this,
config: const ElasticSheetConfig.snappy(),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
Then render a controlled sheet:
ElasticSheet.controlled(
controller: controller,
anchor: ElasticSheetAnchor.centerRight,
collapsedSize: const Size(220, 52),
expandedSize: const Size(320, 320),
collapsedChild: const Text('Compose'),
expandedChild: const Text('Composer panel'),
)
Anchors #
Use anchor to keep a specific edge or corner fixed while the surface grows:
ElasticSheet(
isExpanded: isOpen,
anchor: ElasticSheetAnchor.topRight,
collapsedSize: const Size(180, 48),
expandedSize: const Size(320, 280),
collapsedChild: const Text('Filters'),
expandedChild: const Text('Expanded content'),
)
For ElasticSheetExpandedSizing.dynamicHeight, the horizontal part of the anchor is normalized to the center column, so topLeft and topRight behave like topCenter.
Partial Triggers #
ElasticSheet.controlled injects ElasticSheetActions around collapsed and expanded content. Any descendant can open, close, toggle, or pulse the surface without turning the whole child into one large button.
ElasticSheet.controlled(
controller: controller,
anchor: ElasticSheetAnchor.bottomCenter,
collapsedSize: const Size(320, 56),
expandedSize: const Size(320, 220),
collapsedChild: Builder(
builder: (context) => Row(
children: [
const Expanded(child: TextField()),
IconButton(
onPressed: () => ElasticSheetActions.of(context).expand(),
icon: const Icon(Icons.add_rounded),
),
],
),
),
expandedChild: const Text('Composer actions'),
)
Content States #
Use contentState when a collapsed surface does not always have expanded data.
ElasticSheet(
isExpanded: false,
contentState: ElasticSheetContentState.pending,
collapsedSize: const Size(180, 48),
collapsedChild: const Text('Waiting for slot data'),
onPendingTap: reloadSlots,
)
ready: normal expand/collapse behavior.expandedSizeandexpandedChildare required.pending: no expanded content yet. The surface stays collapsed and plays a subtle pulse on tap.unavailable: visible but disabled. No pulse and no expansion.
Example App #
The runnable showcase lives in example/. It imports elastic_sheet the same way a package consumer would and includes:
- Interactive playground with live spring controls.
- Responsive browser demo for GitHub Pages.
- Care Desk unified showcase.
- Checkout showcase.
Run it locally:
cd example
flutter run -d chrome
Deploy Live Demo #
The GitHub Pages workflow builds the example app with:
cd example
flutter build web --release --base-href "/elastic_sheet/"
In GitHub repository settings, configure Pages to use GitHub Actions as the source. The workflow publishes example/build/web.
License #
MIT. See LICENSE.



