virtual_keypad 0.6.1 copy "virtual_keypad: ^0.6.1" to clipboard
virtual_keypad: ^0.6.1 copied to clipboard

A customizable Flutter virtual keyboard and keypad for kiosk, PIN, password, and TextField input. Supports standalone mode, custom layouts, 12 languages, and theming.

Virtual Keypad

pub package pub points pub likes CI Documentation License: MIT Platform Live Demo

A customizable virtual keyboard, on-screen keyboard, and keypad for Flutter.
Built for kiosk apps, touchscreen and desktop input, PIN and password entry, numeric keypad and numpad flows, and custom TextField integration.

Demo 1 Demo 2 Demo 3

Features #

  • 🎹 Multiple Layouts - Text, numeric, phone, email, URL, or fully custom
  • 🌍 Multi-Language - 12 built-in languages, easily extensible
  • 🔌 Standalone Mode - Works with any standard Flutter TextField or TextFormField
  • 🎯 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

Common Use Cases #

If you're looking for a Flutter virtual keyboard, on-screen keyboard, keypad, numeric keypad, numpad, PIN pad, custom keyboard, or multilingual keyboard, this package is designed for those flows.

  • Use it as a kiosk keyboard, touchscreen keyboard, or desktop keyboard when the system keyboard is unavailable, unwanted, or too limited.
  • Build a numeric keypad, numpad, PIN pad, or OTP keypad for authentication, amount entry, checkout, payment, ATM, POS, and self-service input screens.
  • Create a custom keyboard for password fields, email and URL forms, search actions, send actions, call actions, and app-specific input flows.
  • Add multilingual keyboard behavior with built-in language switching, custom language registration, and direct TextField or TextFormField integration for kiosk, embedded, and enterprise Flutter apps.

Supported Languages #

All 12 languages are registered automatically when you call initializeKeyboardLayouts().

Code Language Native Name Layout Script RTL
ar Arabic العربية Arabic IBM PC Arabic
bn Bengali বাংলা Bengali Bengali
de German Deutsch QWERTZ Latin
en English English QWERTY Latin
es Spanish Español QWERTY (ES) Latin
fr French Français AZERTY Latin
hi Hindi हिन्दी Devanagari Devanagari
ko Korean 한국어 Dubeolsik (두벌식) Hangul
pt Portuguese Português QWERTY (PT) Latin
ru Russian Русский ЙЦУКЕН (JCUKEN) Cyrillic
th Thai ไทย Kedmanee Thai
tr Turkish Türkçe QWERTY (TR) Latin

Note: If you notice any incorrect characters, missing keys, or layout mismatches for a language you are fluent in, feel free to fix it and create a pull request. Community contributions are welcome!

Installation #

dependencies:
  virtual_keypad: ^latest

Quick Start #

Standalone Mode (works with any TextField or TextFormField) #

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, making it useful for existing Flutter forms, kiosk screens, login flows, and embedded touchscreen UIs.

For custom submit-style keys in standalone mode, use onStandaloneInputAction to distinguish actions like call, search, or send at the keyboard level:

VirtualKeypad(
  standalone: true,
  type: KeyboardType.custom,
  customLayout: [
    [VirtualKey.action(action: KeyAction.call)],
  ],
  onStandaloneInputAction: (action, text) {
    if (action == KeyAction.call) {
      placeCall(text);
    }
  },
)

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.

Which Mode Should You Use? #

Mode Best For Use These Widgets
Standalone Fast integration with existing TextField / TextFormField UIs TextField + VirtualKeypad(standalone: true)
Scoped Full control over submit handling, focus-driven layout changes, and system keyboard blocking VirtualKeypadScope + VirtualKeypadTextField + VirtualKeypad()

Choose standalone mode when you want a Flutter virtual keyboard or keypad to drop into an existing form with minimal refactoring. Choose scoped mode when you need predictable focus routing, custom submit handling, secure input behavior, or tighter control for complex form, kiosk, or authentication flows.

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 #

Use these keyboard types to switch between general text input, email keyboard layouts, URL keyboard layouts, numeric keypad input, phone dialer input, and custom keypad flows.

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 #

Custom layouts are useful for building a PIN pad, OTP keypad, numeric keypad, checkout keypad, ATM keypad, POS keypad, or any branded on-screen keyboard flow.

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,
)

customLayout must be used together with type: KeyboardType.custom. Invalid combinations assert immediately in debug mode so setup mistakes fail fast for custom keyboard, custom keypad, PIN pad, and numpad setups.

Theming #

The theming API helps you match the keyboard to kiosk apps, enterprise dashboards, POS interfaces, embedded displays, and branded login or checkout screens.

// 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 #

Use multi-language support when you need a multilingual keyboard for international forms, regional kiosk deployments, localized checkout flows, or RTL input experiences.

initializeKeyboardLayouts(); // Registers all 12 languages

// Switch language
KeyboardLayoutProvider.instance.setLanguage('ar'); // Arabic
KeyboardLayoutProvider.instance.setLanguage('ko'); // Korean
KeyboardLayoutProvider.instance.setLanguage('en'); // English

VirtualKeypad(
  availableLanguages: ['en', 'bn', 'ar'],
  initialLanguage: 'en',
  onLanguageChanged: (code) {
    // Save the selected language if you want to restore it next launch.
  },
)

When availableLanguages contains more than one language, users can long-press the space bar to open the language picker. The first language in the list is the fallback language for that keyboard.

The selected language is remembered for the current app session through the shared keyboard layout provider. If you want to restore the same language after an app restart, save the code from onLanguageChanged and pass it back through initialLanguage.

Adding a Custom Language #

final myLanguage = KeyboardLanguage(
  code: 'xx',
  name: 'MyLanguage',
  nativeName: 'MyLanguage',
  textLayouts: KeyboardLayoutSet(
    primary: textPrimaryLayout,
    secondary: symbolsLayout,
    tertiary: moreSymbolsLayout,
  ),
);

KeyboardLayoutProvider.instance.registerLanguage(myLanguage);
KeyboardLayoutProvider.instance.setLanguage('xx');

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
  availableLanguages: ['en', 'bn'],  // Optional in-keyboard language picker
  initialLanguage: 'en',             // Startup language for this session
  hideWhenUnfocused: false,          // Auto-hide animation
  customLayout: null,                // Custom key arrangement
  onKeyPressed: (key) {},            // Key press callback
  onStandaloneInputAction: (action, text) {}, // Standalone submit-style action callback
  onLanguageChanged: (code) {},      // Language switch 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 virtual keyboard, keypad, PIN pad, password, numeric input, and multilingual keyboard flows.

Common Setup Mistakes #

  • Forgetting initializeKeyboardLayouts() before runApp(). Built-in layouts are registered there.
  • Mixing standalone mode and scoped mode in the same form without a clear reason. Pick one architecture per flow.
  • Providing customLayout without type: KeyboardType.custom, or setting type: KeyboardType.custom without a layout.
  • Expecting VirtualKeypadTextField to allow the system keyboard by default. It blocks physical/system keyboard input unless allowPhysicalKeyboard: true.

Documentation #

These guides cover virtual keyboard integration, keypad customization, multilingual layout setup, and Flutter TextField or TextFormField onboarding.

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

Focused Imports #

Import Best For
package:virtual_keypad/virtual_keypad.dart Full package surface with widgets, layouts, themes, and helpers
package:virtual_keypad/widgets.dart Scoped widget workflows with VirtualKeypadScope and VirtualKeypadTextField
package:virtual_keypad/standalone.dart Standard TextField integration with VirtualKeypad(standalone: true)
package:virtual_keypad/layouts.dart Language registration, layout access, and custom language setup

Contributing #

Contributions welcome! See the Contributing Guide.

License #

MIT License - see LICENSE for details.


Made with ❤️ by Masum

17
likes
160
points
326
downloads

Documentation

API reference

Publisher

verified publisheralmasum.dev

Weekly Downloads

A customizable Flutter virtual keyboard and keypad for kiosk, PIN, password, and TextField input. Supports standalone mode, custom layouts, 12 languages, and theming.

Repository (GitHub)
View/report issues
Contributing

Topics

#keyboard #virtual-keyboard #onscreen-keyboard #multilingual-keyboard #flutter-keyboard

License

MIT (license)

Dependencies

flutter

More

Packages that depend on virtual_keypad