๐ฑ keyboard_safe
A lightweight Flutter widget that prevents keyboard overflow by automatically adjusting padding and optionally scrolling input fields into view.
โ Why KeyboardSafe?
Flutter apps often struggle with keyboard handling, especially in complex forms.
KeyboardSafe solves this with a single, configurable wrapper that offers:
- โ Automatically adjusts padding when the keyboard appears
- ๐ฏ Auto-scrolls to focused input fields
- ๐ Optional sticky footer support above the keyboard
- ๐ Tap outside to dismiss keyboard
- ๐ฆ Optional SafeArea wrapping
- ๐ฌ Smooth animated transitions
๐ง Install it
Add it to your pubspec.yaml:
dependencies:
keyboard_safe: ^0.0.1
Then run:
flutter pub get
๐จ Usage
Wrap your form or layout with KeyboardSafe:
import 'package:keyboard_safe/keyboard_safe.dart';
@override
Widget build(BuildContext context) {
return KeyboardSafe(
scroll: true,
dismissOnTapOutside: true,
footer: ElevatedButton(
onPressed: () {},
child: const Text('Submit'),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: const [
TextField(decoration: InputDecoration(labelText: 'Email')),
SizedBox(height: 16),
TextField(decoration: InputDecoration(labelText: 'Password')),
],
),
);
}
Advanced Example
import 'package:keyboard_safe/keyboard_safe.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('KeyboardSafe Advanced Example'),
),
body: KeyboardSafe(
scroll: true,
autoScrollToFocused: true,
dismissOnTapOutside: true,
persistFooter: true,
safeArea: true,
padding: const EdgeInsets.all(24),
keyboardAnimationDuration: const Duration(milliseconds: 300),
keyboardAnimationCurve: Curves.easeInOut,
onKeyboardChanged: (visible, height) {
debugPrint('Keyboard is ${visible ? 'visible' : 'hidden'} ($height px)');
},
footer: Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: ElevatedButton.icon(
onPressed: () {
KeyboardSafe.dismissKeyboard(context);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Form submitted')),
);
},
icon: const Icon(Icons.send),
label: const Text('Submit'),
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: const [
TextField(
decoration: InputDecoration(
labelText: 'Full Name',
hintText: 'Enter your name',
),
),
SizedBox(height: 16),
TextField(
decoration: InputDecoration(
labelText: 'Email',
hintText: 'you@example.com',
),
),
SizedBox(height: 16),
TextField(
decoration: InputDecoration(
labelText: 'Message',
hintText: 'Type something...',
),
maxLines: 4,
),
],
),
),
);
}
๐ฑ Example App
The example/ app demonstrates the benefits of using KeyboardSafe:
โ
Includes a toggle for 'With' vs 'Without KeyboardSafe'
โ
Demonstrates auto-scroll to input, sticky footer, keyboard avoidance, and tap-outside dismissal
To run:
flutter run example
๐ก If you use FVM, replace
flutterwithfvm flutterin the command above.
๐ฌ Demo
Here's a quick demo of KeyboardSafe in action ๐
๐งช Try it on DartPad
Want to test it live? Here's a minimal demo running in DartPad ๐
๐งช Run the DartPad demo locally
To run the DartPad-compatible demo on your device/emulator:
# Make sure you're in the example/ folder
cd example
# Then run the custom demo entry point
flutter run -t lib/dartpad_demo.dart
๐ก If you use FVM, replace
flutterwithfvm flutterin the command above.
๐ฆ Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
child |
Widget |
โ (required) | Main content inside the wrapper |
footer |
Widget? |
null |
Optional footer shown above the keyboard (e.g. Submit button) |
scroll |
bool |
false |
Whether to wrap in SingleChildScrollView |
autoScrollToFocused |
bool |
true |
Automatically scroll focused field into view |
dismissOnTapOutside |
bool |
false |
Tap anywhere to dismiss keyboard |
safeArea |
bool |
false |
Wrap in a SafeArea widget |
persistFooter |
bool |
false |
Whether footer should remain visible when keyboard appears |
padding |
EdgeInsets |
EdgeInsets.zero |
Base padding applied before keyboard adjustment |
reverse |
bool |
false |
Reverses scroll direction |
onKeyboardChanged |
void Function(bool, double)? |
null |
Callback when keyboard appears/disappears |
keyboardAnimationDuration |
Duration |
Duration(milliseconds: 250) |
Duration of keyboard transitions |
keyboardAnimationCurve |
Curve |
Curves.easeOut |
Curve used in AnimatedPadding and AnimatedContainer |
โจ๏ธ Dismiss Keyboard
You can programmatically dismiss the keyboard using:
KeyboardSafe.dismissKeyboard(context);
๐งช Testing
This package includes widget tests that verify key behaviors:
flutter test
Covered features:
โ
Padding applied when MediaQuery.viewInsets.bottom is non-zero
โ
Keyboard dismissal when tapping outside of input
๐ License
MIT License. See LICENSE for details.
๐ก Contribute
Feel free to file issues or submit PRs to help improve this package.
Star โญ the repo if you found this helpful!
๐ฌ Maintainer
Made by @ChathraNavoda