keyboard_safe 1.0.0 copy "keyboard_safe: ^1.0.0" to clipboard
keyboard_safe: ^1.0.0 copied to clipboard

A lightweight Flutter widget that prevents keyboard overflow by automatically adjusting layout, scrolling input fields into view, and providing sticky footers above the keyboard.

πŸ“± keyboard_safe #

A comprehensive Flutter widget that eliminates keyboard overflow issues with intelligent layout management, auto-scrolling, and smooth animations.

pub package License: MIT GitHub stars CI


🌟 Why KeyboardSafe? #

Keyboard handling is one of Flutter's biggest pain points. KeyboardSafe transforms this challenge into a seamless experience with a single, powerful wrapper that provides:

  • βœ… Smart Layout Management: Automatically adjusts padding when keyboard appears/disappears
  • 🎯 Auto-Scroll Intelligence: Focused input fields scroll into view automatically
  • πŸ“Œ Flexible Footer Support: Choose between sticky footers or screen-bottom placement
  • πŸ‘† Tap-to-Dismiss: Native-like keyboard dismissal when tapping outside
  • πŸ›‘οΈ SafeArea Integration: Optional SafeArea wrapping for notched devices
  • 🎬 Buttery Smooth Animations: Configurable duration and curves for all transitions
  • πŸ“± UX-First Design: Built with mobile app best practices in mind

Perfect for forms, chat interfaces, login screens, and any app with text input!


πŸš€ Quick Start #

Installation #

Add to your pubspec.yaml:

dependencies:
  keyboard_safe: ^1.0.0

Then run:

flutter pub get

Basic Usage #

Transform your forms in seconds:

import 'package:keyboard_safe/keyboard_safe.dart';

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: KeyboardSafe(
      scroll: true,
      dismissOnTapOutside: true,
      footer: ElevatedButton(
        onPressed: _submitForm,
        child: const Text('Submit'),
      ),
      child: Column(
        children: [
          TextField(decoration: InputDecoration(labelText: 'Email')),
          SizedBox(height: 16),
          TextField(decoration: InputDecoration(labelText: 'Password')),
        ],
      ),
    ),
  );
}

That's it! Your form now handles keyboard overflow, auto-scrolls to focused fields, and includes a responsive footer.


🎯 Complete Example #

Here's a production-ready form showcasing all features:

import 'package:flutter/material.dart';
import 'package:keyboard_safe/keyboard_safe.dart';

class LoginScreen extends StatefulWidget {
  @override
  _LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final _formKey = GlobalKey<FormState>();
  bool _isKeyboardVisible = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Login'),
        backgroundColor: Colors.transparent,
        elevation: 0,
      ),
      body: KeyboardSafe(
        // Enable scrolling for better UX
        scroll: true,

        // Auto-scroll focused fields into view
        autoScrollToFocused: true,

        // Tap anywhere to dismiss keyboard
        dismissOnTapOutside: true,

        // Respect device safe areas
        safeArea: true,

        // Add consistent padding
        padding: EdgeInsets.all(24),

        // Customize animation timing
        keyboardAnimationDuration: Duration(milliseconds: 300),
        keyboardAnimationCurve: Curves.easeInOut,

        // Track keyboard state changes
        onKeyboardChanged: (visible, height) {
          setState(() => _isKeyboardVisible = visible);
          print('Keyboard ${visible ? 'shown' : 'hidden'}: ${height}px');
        },

        // Footer stays at screen bottom (recommended UX)
        footer: Container(
          width: double.infinity,
          padding: EdgeInsets.symmetric(vertical: 16),
          child: ElevatedButton(
            onPressed: () {
              // Dismiss keyboard before processing
              KeyboardSafe.dismissKeyboard(context);
              _handleLogin();
            },
            style: ElevatedButton.styleFrom(
              backgroundColor: Theme.of(context).primaryColor,
              foregroundColor: Colors.white,
              padding: EdgeInsets.symmetric(vertical: 16),
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(12),
              ),
            ),
            child: Text(
              _isKeyboardVisible ? 'Login' : 'Login to Continue',
              style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
            ),
          ),
        ),

        child: Form(
          key: _formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              // Logo or header
              Container(
                height: 120,
                margin: EdgeInsets.only(bottom: 32),
                child: Icon(
                  Icons.lock_outline,
                  size: 64,
                  color: Theme.of(context).primaryColor,
                ),
              ),

              // Email field
              TextFormField(
                keyboardType: TextInputType.emailAddress,
                textInputAction: TextInputAction.next,
                decoration: InputDecoration(
                  labelText: 'Email Address',
                  hintText: 'you@example.com',
                  prefixIcon: Icon(Icons.email_outlined),
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(12),
                  ),
                ),
                validator: (value) {
                  if (value?.isEmpty ?? true) {
                    return 'Please enter your email';
                  }
                  return null;
                },
              ),

              SizedBox(height: 16),

              // Password field
              TextFormField(
                obscureText: true,
                textInputAction: TextInputAction.done,
                decoration: InputDecoration(
                  labelText: 'Password',
                  hintText: 'Enter your password',
                  prefixIcon: Icon(Icons.lock_outlined),
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(12),
                  ),
                ),
                validator: (value) {
                  if (value?.isEmpty ?? true) {
                    return 'Please enter your password';
                  }
                  return null;
                },
              ),

              SizedBox(height: 24),

              // Additional options
              Row(
                children: [
                  Icon(Icons.info_outline, size: 16, color: Colors.grey),
                  SizedBox(width: 8),
                  Expanded(
                    child: Text(
                      'Forgot password? Tap here to reset',
                      style: TextStyle(color: Colors.grey[600]),
                    ),
                  ),
                ],
              ),

              SizedBox(height: 20), // Extra space before footer
            ],
          ),
        ),
      ),
    );
  }

  void _handleLogin() {
    if (_formKey.currentState?.validate() ?? false) {
      // Process login
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Login successful!')),
      );
    }
  }
}

πŸ“¦ API Reference #

KeyboardSafe Parameters #

Parameter Type Default Description
child Widget required Main content inside the wrapper
footer Widget? null Optional footer (e.g. Submit button) shown above keyboard
scroll bool false Wraps content in SingleChildScrollView for tall layouts
autoScrollToFocused bool true Auto-scrolls focused input fields into view
dismissOnTapOutside bool false Dismisses keyboard when tapping outside input fields
safeArea bool false Wraps layout in SafeArea widget
persistFooter bool false If true, footer floats above keyboard (can feel intrusive)
padding EdgeInsets EdgeInsets.zero Additional padding around content
reverse bool false Reverses scroll direction (useful for chat interfaces)
onKeyboardChanged Function(bool, double)? null Callback when keyboard visibility changes
keyboardAnimationDuration Duration 250ms Duration of keyboard-related animations
keyboardAnimationCurve Curve Curves.easeOut Animation curve for smooth transitions

Static Methods #

// Dismiss keyboard programmatically
KeyboardSafe.dismissKeyboard(context);

🎨 Usage Patterns #

1. Simple Forms #

KeyboardSafe(
  scroll: true,
  child: YourFormContent(),
)

2. Forms with Submit Button #

KeyboardSafe(
  scroll: true,
  footer: SubmitButton(),
  child: YourFormContent(),
)

3. Chat Interface #

KeyboardSafe(
  scroll: true,
  reverse: true, // New messages at bottom
  persistFooter: true, // Keep input visible
  footer: MessageInput(),
  child: MessageList(),
)

4. Full-Screen Experience #

KeyboardSafe(
  safeArea: true,
  dismissOnTapOutside: true,
  padding: EdgeInsets.all(16),
  child: YourContent(),
)

persistFooter: false (Recommended)

  • Footer stays at screen bottom
  • Provides familiar mobile app experience
  • Better for submit buttons and navigation

persistFooter: true (Use Sparingly)

  • Footer floats above keyboard
  • Can feel intrusive in most contexts
  • Good for chat apps where input must stay visible

🎬 Demo #

See the dramatic difference KeyboardSafe makes:

πŸ“± Side-by-Side Comparison #

Without KeyboardSafe With KeyboardSafe
Without KeyboardSafe - Broken UX With KeyboardSafe - Perfect UX
❌ Footer covers form fields
❌ No auto-scroll
❌ Manual keyboard handling
❌ Broken user experience
βœ… Smart layout management
βœ… Auto-scroll to focused fields
βœ… Tap-to-dismiss keyboard
βœ… Seamless user experience

🎯 The Problem vs Solution #

The Problem (Left): Typical Flutter keyboard issues that frustrate users:

  • Footer floats up and covers input fields
  • No automatic scrolling to focused fields
  • Users must manually dismiss keyboard
  • Broken layouts and poor UX

The Solution (Right): KeyboardSafe transforms the experience:

  • Intelligent layout adjustment
  • Automatic field focusing and scrolling
  • Native-like tap-to-dismiss behavior
  • Professional, polished user experience

πŸ§ͺ Try it Live #

Experience the difference yourself:

Open in DartPad

Run Example App #

cd example
flutter run

Run DartPad Demo Locally #

cd example
flutter run -t lib/dartpad_demo.dart

πŸ§ͺ Testing #

KeyboardSafe includes comprehensive widget tests:

flutter test

Test Coverage:

  • βœ… Keyboard padding application
  • βœ… Auto-scroll to focused fields
  • βœ… Footer positioning behavior
  • βœ… Tap-outside dismissal
  • βœ… Animation timing
  • βœ… SafeArea integration

πŸ”„ Migration Guide #

From v0.0.x to v1.0.0 #

v1.0.0 introduces powerful new features while maintaining backward compatibility:

βœ… No Breaking Changes: Existing code continues to work
πŸ†• New Features: Enhanced footer control, better animations, improved UX
πŸ“– Better Docs: Comprehensive examples and usage patterns

Recommended Updates:

// Before (still works)
KeyboardSafe(child: MyForm())

// After (recommended)
KeyboardSafe(
  scroll: true,
  dismissOnTapOutside: true,
  footer: MySubmitButton(),
  child: MyForm(),
)

🀝 Contributing #

We welcome contributions! Here's how you can help:

  1. πŸ› Report Issues: Found a bug? Open an issue
  2. πŸ’‘ Suggest Features: Have ideas? We'd love to hear them
  3. πŸ”§ Submit PRs: Improvements and fixes are always welcome
  4. ⭐ Star the Repo: Help others discover this package

Development Setup #

git clone https://github.com/ChathraNavoda/keyboard_safe.git
cd keyboard_safe
flutter pub get
flutter test

πŸ“Š Package Stats #

  • 🎯 100% Dart: Pure Flutter implementation
  • πŸ“± All Platforms: iOS, Android, Web, Desktop
  • πŸ§ͺ Well Tested: Comprehensive test suite
  • πŸ“– Fully Documented: Every API has detailed docs
  • πŸš€ Production Ready: Used in real-world apps

πŸ“„ License #

MIT License - see LICENSE for details.


πŸ’ͺ Built by the Community #

KeyboardSafe started as a solution to a common Flutter problem and evolved into a comprehensive package thanks to community feedback and real-world usage.

Made by @ChathraNavoda


If KeyboardSafe saved you time and headaches, consider starring ⭐ the repo to help others discover it!

19
likes
160
points
277
downloads

Publisher

unverified uploader

Weekly Downloads

A lightweight Flutter widget that prevents keyboard overflow by automatically adjusting layout, scrolling input fields into view, and providing sticky footers above the keyboard.

Repository (GitHub)
View/report issues

Topics

#keyboard #layout #textfields #overflow #focus

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on keyboard_safe