Virtual Keypad

pub package License: MIT Platform

A fully customizable virtual on-screen keyboard for Flutter.
Perfect for kiosk apps, password UIs, and custom input interfaces.

Demo 1 Demo 2 Demo 3

Features

  • 🎹 Multiple Layouts - Text, numeric, phone, email, URL, or fully custom
  • 🌍 Multi-Language - Built-in English, Bengali & French, easily extensible
  • 🔌 Standalone Mode - Works with any standard Flutter TextField
  • 🎯 Standalone Scope - Restrict keyboard to a widget subtree
  • 🔤 Smart TextField - Auto-adapts keyboard layout based on input type
  • 🎨 Fully Customizable - Light, dark, or fully custom themes
  • 📱 Cross-Platform - Works on iOS, Android, Web, macOS, Windows, Linux
  • ✂️ Full Editing - Selection, copy/paste, cursor control
  • 👆 Key Preview - Native-style key press popup feedback
  • 🫥 Auto-Hide - Animated show/hide on focus change

Installation

dependencies:
  virtual_keypad: ^latest

Quick Start

Standalone Mode (works with any TextField)

import 'package:virtual_keypad/virtual_keypad.dart';

void main() {
  initializeKeyboardLayouts();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(controller: controller),
        VirtualKeypad(standalone: true),
      ],
    );
  }
}

Just add standalone: true — no wrapper widgets needed. The keyboard auto-detects focused fields and adapts layout based on keyboardType.

Scoped Standalone Mode

Wrap with VirtualKeypadStandaloneScope to restrict the keyboard to a specific subtree (useful in Widgetbook or multi-panel UIs):

VirtualKeypadStandaloneScope(
  child: Column(
    children: [
      TextField(controller: controller),
      VirtualKeypad(standalone: true),
    ],
  ),
)

Fields outside the scope won't trigger this keyboard.

Scope Mode (full control)

import 'package:virtual_keypad/virtual_keypad.dart';

void main() {
  initializeKeyboardLayouts();
  runApp(MyApp());
}

class _MyAppState extends State<MyApp> {
  final controller = VirtualKeypadController();

  @override
  Widget build(BuildContext context) {
    return VirtualKeypadScope(
      child: Column(
        children: [
          VirtualKeypadTextField(
            controller: controller,
            decoration: InputDecoration(labelText: 'Enter text'),
          ),
          VirtualKeypad(),
        ],
      ),
    );
  }
}

Three components work together: VirtualKeypadScopeVirtualKeypadTextFieldVirtualKeypad. Use this mode for selection callbacks, submit handling, and physical keyboard blocking.

Keyboard Types

VirtualKeypadTextField(
  controller: controller,
  keyboardType: KeyboardType.emailAddress, // Auto-shows @ and .
)
Type Use Case
text General text input (QWERTY)
emailAddress Email fields (QWERTY + @ .)
url URL fields (QWERTY + / : .)
number Numeric input (0-9)
phone Phone dialer
multiline Text areas with newline
custom User-defined layouts

Custom Layout

final pinLayout = [
  [
    VirtualKey.character(text: '1'),
    VirtualKey.character(text: '2'),
    VirtualKey.character(text: '3'),
  ],
  [
    VirtualKey.character(text: '4'),
    VirtualKey.character(text: '5'),
    VirtualKey.character(text: '6'),
  ],
  [
    VirtualKey.character(text: '7'),
    VirtualKey.character(text: '8'),
    VirtualKey.character(text: '9'),
  ],
  [
    VirtualKey.action(action: KeyAction.backSpace),
    VirtualKey.character(text: '0'),
    VirtualKey.action(action: KeyAction.done, label: '✓'),
  ],
];

VirtualKeypad(
  type: KeyboardType.custom,
  customLayout: pinLayout,
)

Theming

// Built-in themes
VirtualKeypad(theme: VirtualKeypadTheme.light)
VirtualKeypad(theme: VirtualKeypadTheme.dark)

// Custom theme
VirtualKeypad(
  theme: VirtualKeypadTheme(
    backgroundColor: Colors.grey[900]!,
    keyColor: Colors.grey[800]!,
    actionKeyColor: Colors.grey[700]!,
    keyTextColor: Colors.white,
    keyBorderRadius: 12,
  ),
)

// Modify existing theme
VirtualKeypad(
  theme: VirtualKeypadTheme.dark.copyWith(
    keyBorderRadius: 12,
    keyTextSize: 24,
  ),
)
Property Type Default Description
backgroundColor Color #D1D3D9 Keyboard background
keyColor Color #FFFFFF Character key background
actionKeyColor Color #ADB3BC Action key background
keyTextColor Color #1C1C1E Text/icon color
keyTextSize double 22.0 Font size
keyBorderRadius double 6.0 Corner radius
keyShadow bool true Show key shadows
splashColor Color? null Tap ripple color

Multi-Language

initializeKeyboardLayouts(); // Registers English & Bengali

// Switch language
KeyboardLayoutProvider.instance.setLanguage('bn'); // Bengali
KeyboardLayoutProvider.instance.setLanguage('en'); // English
Code Language Layout
en English QWERTY
bn Bengali বাংলা
fr French AZERTY

Adding a Custom Language

final spanishLanguage = KeyboardLanguage(
  code: 'es',
  name: 'Spanish',
  nativeName: 'Español',
  textLayouts: KeyboardLayoutSet(
    primary: textPrimaryLayout,
    secondary: symbolsLayout,
    tertiary: moreSymbolsLayout,
  ),
);

KeyboardLayoutProvider.instance.registerLanguage(spanishLanguage);
KeyboardLayoutProvider.instance.setLanguage('es');

API Reference

VirtualKeypadTextField

VirtualKeypadTextField(
  controller: controller,           // Required
  keyboardType: KeyboardType.text,   // Layout type
  obscureText: false,                // Password mode
  allowPhysicalKeyboard: false,      // Block system keyboard
  maxLength: null,                   // Character limit
  maxLines: 1,                       // Line count (null = unlimited)
  onChanged: (value) {},             // Text change callback
  onSubmitted: (value) {},           // Submit callback
)

VirtualKeypad

VirtualKeypad(
  standalone: false,                 // true = works with any TextField
  type: null,                        // Override layout (auto if null)
  height: 280,                       // Keyboard height
  theme: VirtualKeypadTheme.light,   // Visual theme
  hideWhenUnfocused: false,          // Auto-hide animation
  customLayout: null,                // Custom key arrangement
  onKeyPressed: (key) {},            // Key press callback
)

VirtualKeypadController

final controller = VirtualKeypadController();

controller.insertText('Hello');    // Insert at cursor
controller.deleteBackward();       // Delete before cursor
controller.selectAll();            // Select all text
controller.clear();                // Clear all
controller.cursorPosition = 5;     // Set cursor position
controller.moveCursorLeft();       // Move cursor
controller.moveCursorRight();

Examples

Check out the example directory for a complete demo app with 9 screens showcasing all features.

Documentation

Guide Description
API Reference Complete API documentation
Custom Layouts Build custom keyboard layouts
Adding Languages Add new language support
Theming Customize keyboard appearance

Contributing

Contributions welcome! See the Contributing Guide.

License

MIT License - see LICENSE for details.


Made with ❤️ by Masum

Libraries

virtual_keypad
A Flutter package for creating customizable virtual on-screen keyboards.