capacitor-keyboard
Guide to handling keyboard in Capacitor apps including visibility detection, accessory bar, scroll behavior, and input focus. Use this skill when users have keyboard-related issues.
By cap-go · 856 installs
npx skills add cap-go/capgo-skills --skill capacitor-keyboard
Source repository · Upstream listing
Keyboard Handling in Capacitor
When to Use
TRIGGER when:
Focused input is covered by the keyboard, or the page scrolls unexpectedly
Chat composer / fixed footer does not stick to the keyboard
White or black band above the keyboard (Android 15+ edge to edge, iOS backdrop)
100vh / dvh layout collapses when the keyboard opens
iOS zooms into inputs, or the QuickType/accessory bar looks wrong
Keyboard events never fire or fire twice
Do not use:
Notch / home indicator / status bar padding: safe area handling
Ionic ion input , ion footer styling: ionic design
Labels, focus order, screen readers: capacitor accessibility
Platform model (the key decision)
iOS Android
Who resizes Plugin, per resize mode OS + WebView; resize config is ignored
Events keyboardWillShow before animation, keyboardDidShow after Will/Did fire almost together
JS control setResizeMode , getResizeMode , setScroll , setStyle , setAccessoryBarVisible (iPhone only) show() (Android only), hide()
iOS resize modes ( KeyboardResize enum):
Mode Effect Use when
native (default) Whole WebView shrinks; vh units change Plain web apps; simplest
body Only <body height changes; vh unchanged Layouts that rely on stable vh
ionic Only ion app resizes Ionic Framework apps only
none Nothing resizes; you position with keyboard height Custom chat UIs, full control
Workflow
1. Inspect : capacitor.config. plugins.Keyboard , @capacitor/keyboard version (8.0.4+ includes iOS 26 and Android SystemBars fixes), whether Ionic is used, @capacitor/status bar / SystemBars config, and the failing screen's CSS ( position: fixed , 100vh ).
2. Reproduce on a device (simulators often use a hardware keyboard: iOS Simulator I/O Keyboard Toggle Software Keyboard).
3. Pick the iOS resize mode from the table; set it in config, not at runtime, unless one screen needs a different mode.
4. Fix Android separately (below).
5. Verify.
Config
String values in JSON config are uppercase for style ( "DARK" ), lowercase for resize ( "body" ).
Custom positioning ( resize: none or chat UIs)
Use max() , not + : while the keyboard is up the home indicator inset is already covered.
Android notes
Android 15+ (targetSdk 35) enforces edge to edge; Android 16 (targetSdk 36, Capacitor 8 default) removes the opt out. The WebView now draws under system bars, so the keyboard inset must be handled. @capacitor/keyboard 7.0.2 fixed white space above the keyboard on Android 15+, and 8.0.3 fixed the interaction with the SystemBars core plugin. Update the plugin before writing workarounds.
resizeOnFullScreen: true was the Capacitor <= 7 workaround for fullscreen / overlaid status bar. On Capacitor 8+ the SystemBars core plugin handles IME insets and logs You should omit Keyboard.resizeOnFullScreen in your capacitor.config.json . Other values can lead to unexpected behavior. unless SystemBars.insetsHandling is disable . Remove it.
Do not add android:windowSoftInputMode="adjustPan" to fix overlap; it pans the whole window and breaks fixed headers. The template omits it (default resize behavior).
env(keyboard inset height) and interactive widget viewport meta are Chromium features; test on the target Android System WebView version before relying on them, and never on iOS.
iOS notes
Inputs with computed font size < 16px make iOS zoom on focus. Use font size: 16px (or larger) on inputs; do not disable user zoom globally ( maximum scale=1 ) as it hurts accessibility.
setAccessoryBarVisible({ isVisible: false }) hides the prev/next/done bar on iPhone; it has no effect on iPad.
setScroll({ isDisabled: true }) stops the WebView scroll view from bouncing when the keyboard opens; pair with resize: none for custom layouts.
iOS 26 keyboard regressions and the iPad Magic Keyboard black QuickType bar were fixed in @capacitor/keyboard 8.0.4. If a black/white band appears behind the keyboard, set autoBackdropColor: 'auto' (uses backgroundColor from config, else the DOM body background) or 'dom' .
Verification
1. npx cap sync and run on a physical iPhone and an Android 15+/16 device.
2. For each form screen: focus first and last input; the focused field stays visible; footer sits on the keyboard; no gap above the keyboard; rotating with the keyboard open keeps layout.
3. Dismiss via swipe/back button: keyboardWillHide fires and kb returns to 0.
4. iOS: confirm no zoom on focus; accessory bar state matches the design.
5. Check versions: npm ls @capacitor/keyboard @capacitor/core .
Error Handling
Symptom / message Cause Fix
"Keyboard" plugin is not implemented on web or "Keyboard.setAccessoryBarVisible()" is not implemented on android Plugin/method unavailable on that platform Guard with Capacitor.getPlatform() === 'ios'
show() does nothing on iOS show() is Android only Focus an input from a user gesture instead
Footer floats in the middle after keyboard closes (Android) WebView height not reset when keyboard hides without animation Update to @capacitor/keyboard 8.0.4+
White band above keyboard on Android 15+ Edge to edge insets + old plugin Update plugin (7.0.2+ / 8.0.3+); on Capacitor 8 remove resizeOnFullScreen
Logcat SystemBars: You should omit Keyboard.resizeOnFullScreen ... Legacy config fighting SystemBars inset handling Delete resizeOnFullScreen from config
vh based screen shrinks on iOS resize: native changes viewport Switch to body or none
Ionic content jumps twice resize: native / body plus Ionic's own handling Use resize: 'ionic'
Listeners fire twice after navigation Listener added per page mount, never removed Keep the returned handle and await handle.remove() on unmount
Black QuickType bar on iPad with hardware keyboard Pre 8.0.4 plugin bug Update plugin
Resources
Keyboard plugin API: https://capacitorjs.com/docs/apis/keyboard
Plugin changelog: https://github.com/ionic team/capacitor keyboard/blob/main/CHANGELOG.md
System Bars (edge to edge): https://capacitorjs.com/docs/apis/system bars