[go: up one dir, main page]

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
362
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