virtual_keypad 0.6.1
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.
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.
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 onkeyboardType, 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:
VirtualKeypadScope→VirtualKeypadTextField→VirtualKeypad. 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,
)
customLayoutmust be used together withtype: 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()beforerunApp(). 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
customLayoutwithouttype: KeyboardType.custom, or settingtype: KeyboardType.customwithout a layout. - Expecting
VirtualKeypadTextFieldto allow the system keyboard by default. It blocks physical/system keyboard input unlessallowPhysicalKeyboard: 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