Building A Custom Bottom Sheet System With Snap Points
Jan 21, 2026



Summary
Summary
Summary
Summary
This tutorial shows how to build a custom bottom sheet with snap points in flutter for mobile development. It covers modeling snap points, gesture handling with velocity-aware snapping, animation strategies, layout and accessibility concerns, integration APIs, and edge-case testing to create a reusable production-ready component.
This tutorial shows how to build a custom bottom sheet with snap points in flutter for mobile development. It covers modeling snap points, gesture handling with velocity-aware snapping, animation strategies, layout and accessibility concerns, integration APIs, and edge-case testing to create a reusable production-ready component.
This tutorial shows how to build a custom bottom sheet with snap points in flutter for mobile development. It covers modeling snap points, gesture handling with velocity-aware snapping, animation strategies, layout and accessibility concerns, integration APIs, and edge-case testing to create a reusable production-ready component.
This tutorial shows how to build a custom bottom sheet with snap points in flutter for mobile development. It covers modeling snap points, gesture handling with velocity-aware snapping, animation strategies, layout and accessibility concerns, integration APIs, and edge-case testing to create a reusable production-ready component.
Key insights:
Key insights:
Key insights:
Key insights:
Designing Snap Points: Represent snap points as validated fractions of screen height and convert to pixels at layout time for predictability.
Gesture Handling And Animation: Use pan updates for immediate feedback and velocity-aware logic on pan end to choose a target snap, animating with an AnimationController or physics simulation.
Layout Considerations: Place the sheet in a Stack, respect safe areas and view insets, and coordinate with nested scrollables to avoid gesture conflicts.
Integration And Edge Cases: Expose a small controller API for programmatic snapping, handle orientation changes, and test rapid gestures and small screens.
Performance And Testing: Avoid full rebuilds during drags, isolate heavy children, and use widget/golden tests and semantics checks for robust mobile development.
Introduction
Building a robust custom bottom sheet with snap points is a common requirement in modern flutter mobile development. System bottom sheets (showModalBottomSheet) are great, but custom implementations let you control physics, multiple snap positions, gestures, and accessibility. This tutorial walks through designing snap points, handling gestures and animations, layout concerns, and integration tips so you can build a reusable, production-ready component.
Designing Snap Points
A snap point is a vertical target (in pixels or fraction of screen height) where the sheet rests. Model snap points as a sorted list of doubles (0.0 to 1.0 representing screen height fraction). Convert them to pixels with MediaQuery. Provide at least two snap points: collapsed and expanded. Example model:
class SnapSheetConfig { final List<double> snapFractions; // ascending, 0..1 const SnapSheetConfig(this.snapFractions); }
Choose an API that accepts an initial index and allows programmatic snapping. Keep the configuration immutable to avoid layout thrash. Validate fractions in the constructor and clamp to range.
Gesture Handling And Animation
Gesture handling requires translating vertical drags into sheet offsets and deciding the destination snap based on velocity and current position. Use a StatefulWidget with an AnimationController driving a Tween from current pixel offset to the target offset. OnPanUpdate, update a local offset and call setState for immediate feedback; onPanEnd, compute a target snap index.
Decide target using two signals: drag velocity and proximity. A typical rule: if velocity exceeds a threshold toward a direction, snap to the next point in that direction; otherwise, snap to the nearest point by distance. Use a physics-based curve (Curves.easeOut) or simulate with SpringSimulation for natural motion. Example controller sketch:
// inside State void _animateTo(double targetPx) { _animation = Tween(begin: _currentPx, end: targetPx) .animate(CurvedAnimation(parent: _controller, curve: Curves.easeOut)); _controller ..value = 0 ..forward(); }
Keep velocity handling tight: convert GestureVelocity to px/sec and compare to a small threshold (e.g., 700 px/s). Cancel ongoing animations on new gestures.
Layout Considerations
Place the sheet above your app scaffold content using a Stack so the sheet can overlap. Respect safe areas and keyboard insets by using MediaQuery padding and ViewInsets. When computing pixel positions, subtract top and bottom safe area as appropriate.
Make content inside the bottom sheet scroll-aware. For sheets that contain scrollable children, implement nested gesture coordination: when the child scroll is at its edge and user drags downward/upward, transfer gesture to the sheet. Use NotificationListener to detect overscroll and adjust sheet behavior.
Accessibility: ensure the sheet has a semantic label, supports focus traversal, and exposes its expanded/collapsed state via Semantics. Provide keyboard shortcuts to programmatically snap for desktop/mobile web.
Integration And Edge Cases
Expose a controller API to allow other widgets to snap, expand, collapse, or listen to state changes. Keep APIs small: snapToIndex, expand, collapse, addListener, dispose. Handle orientation changes by recalculating pixel positions from fractions and resuming any in-progress animations toward the new pixel target.
Edge cases to test: very small screens, high-density screens, rapid successive gestures, and nested scrollables. For performance, avoid rebuilding large children on every frame: move heavy widgets into const or separate StatefulWidgets that only rebuild when needed.
Testing: write widget tests that simulate drag gestures using tester.drag and verify final positions and semantics. Use golden tests for visual regressions at important snap positions.
Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.
Conclusion
A custom bottom sheet with snap points in flutter gives you control over UX and physics beyond the platform sheet. Model snap points as fractions, handle gestures with velocity-aware logic, animate with an AnimationController (or physics simulation), and mind layout and accessibility. Provide a small controller API for integration and test the component across device sizes. This architecture yields a predictable, reusable sheet suitable for production mobile development.
Introduction
Building a robust custom bottom sheet with snap points is a common requirement in modern flutter mobile development. System bottom sheets (showModalBottomSheet) are great, but custom implementations let you control physics, multiple snap positions, gestures, and accessibility. This tutorial walks through designing snap points, handling gestures and animations, layout concerns, and integration tips so you can build a reusable, production-ready component.
Designing Snap Points
A snap point is a vertical target (in pixels or fraction of screen height) where the sheet rests. Model snap points as a sorted list of doubles (0.0 to 1.0 representing screen height fraction). Convert them to pixels with MediaQuery. Provide at least two snap points: collapsed and expanded. Example model:
class SnapSheetConfig { final List<double> snapFractions; // ascending, 0..1 const SnapSheetConfig(this.snapFractions); }
Choose an API that accepts an initial index and allows programmatic snapping. Keep the configuration immutable to avoid layout thrash. Validate fractions in the constructor and clamp to range.
Gesture Handling And Animation
Gesture handling requires translating vertical drags into sheet offsets and deciding the destination snap based on velocity and current position. Use a StatefulWidget with an AnimationController driving a Tween from current pixel offset to the target offset. OnPanUpdate, update a local offset and call setState for immediate feedback; onPanEnd, compute a target snap index.
Decide target using two signals: drag velocity and proximity. A typical rule: if velocity exceeds a threshold toward a direction, snap to the next point in that direction; otherwise, snap to the nearest point by distance. Use a physics-based curve (Curves.easeOut) or simulate with SpringSimulation for natural motion. Example controller sketch:
// inside State void _animateTo(double targetPx) { _animation = Tween(begin: _currentPx, end: targetPx) .animate(CurvedAnimation(parent: _controller, curve: Curves.easeOut)); _controller ..value = 0 ..forward(); }
Keep velocity handling tight: convert GestureVelocity to px/sec and compare to a small threshold (e.g., 700 px/s). Cancel ongoing animations on new gestures.
Layout Considerations
Place the sheet above your app scaffold content using a Stack so the sheet can overlap. Respect safe areas and keyboard insets by using MediaQuery padding and ViewInsets. When computing pixel positions, subtract top and bottom safe area as appropriate.
Make content inside the bottom sheet scroll-aware. For sheets that contain scrollable children, implement nested gesture coordination: when the child scroll is at its edge and user drags downward/upward, transfer gesture to the sheet. Use NotificationListener to detect overscroll and adjust sheet behavior.
Accessibility: ensure the sheet has a semantic label, supports focus traversal, and exposes its expanded/collapsed state via Semantics. Provide keyboard shortcuts to programmatically snap for desktop/mobile web.
Integration And Edge Cases
Expose a controller API to allow other widgets to snap, expand, collapse, or listen to state changes. Keep APIs small: snapToIndex, expand, collapse, addListener, dispose. Handle orientation changes by recalculating pixel positions from fractions and resuming any in-progress animations toward the new pixel target.
Edge cases to test: very small screens, high-density screens, rapid successive gestures, and nested scrollables. For performance, avoid rebuilding large children on every frame: move heavy widgets into const or separate StatefulWidgets that only rebuild when needed.
Testing: write widget tests that simulate drag gestures using tester.drag and verify final positions and semantics. Use golden tests for visual regressions at important snap positions.
Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.
Conclusion
A custom bottom sheet with snap points in flutter gives you control over UX and physics beyond the platform sheet. Model snap points as fractions, handle gestures with velocity-aware logic, animate with an AnimationController (or physics simulation), and mind layout and accessibility. Provide a small controller API for integration and test the component across device sizes. This architecture yields a predictable, reusable sheet suitable for production mobile development.
Build Flutter Apps Faster with Vibe Studio
Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.
Other Insights






















