Skip to main content

Bridge functions

Plain functions wrapping the native KeyboardBridge module directly, no object/class to instantiate:

import { commitText } from 'react-native-keyboard-bridge';
<TouchableOpacity onPress={() => commitText('a')}><Text>a</Text></TouchableOpacity>
function commitText(text: string): void;
function deleteSurroundingText(before: number, after: number): void;
function setSelection(start: number, end: number): void;
function getTextBeforeCursor(length: number): Promise<string>;
function getTextAfterCursor(length: number): Promise<string>;
function getSelectedText(): Promise<string>;
function sendKeyEvent(keyCode: number): void;
function performEditorAction(actionCode: number): void;
function switchToPreviousInputMethod(): void;
function hideKeyboard(): void;
function getCursorCapsMode(reqModes?: number): Promise<number>; // defaults to CapsModeRequest.SENTENCES

bridge.ts runs on both platforms: Android's CustomKeyboardService and iOS's KeyboardViewController both host real React Native and both register a native module named KeyboardBridge. Outside either IME/extension process every function here is a safe no-op instead of throwing, so a component that calls them doesn't need to guard for it.

Bridge-function parity table​

UITextDocumentProxy/UIInputViewController (the only API surface a keyboard extension gets on iOS) is a much smaller surface than Android's InputConnection, so parity isn't 1:1. Functions with no iOS implementation are still defined in the iOS native module, as safe no-ops (resolving a safe default when they return a value) — not left undefined — so a shared KeyboardApp.tsx never needs to guard for it.

FunctioniOSNotes
commitText✅textDocumentProxy.insertText
deleteSurroundingText⚠️ partialbefore via repeated deleteBackward(); after silently ignored (no forward-delete API)
getTextBeforeCursor✅textDocumentProxy.documentContextBeforeInput
getTextAfterCursor✅textDocumentProxy.documentContextAfterInput
getSelectedText✅textDocumentProxy.selectedText
getCursorCapsMode⚠️ approximatedheuristic over documentContextBeforeInput, not Android's exact locale-aware algorithm
switchToNextInputMethod✅UIInputViewController.advanceToNextInputMode()
switchToPreviousInputMethod⚠️ approximatediOS has no distinct "previous" — calls the same advanceToNextInputMode()
performHapticFeedback✅*UIImpactFeedbackGenerator; *silently no-ops without user-granted "Allow Full Access" (Apple restriction)
playClickSound⚠️ partialUIDevice.playInputClick(); effect argument accepted but ignored (iOS has one click sound, not per-key-type)
setSelection❌no absolute-offset selection API
getExtractedText❌no ExtractedText-shaped API
sendKeyEvent❌no key-event-injection API
performEditorAction❌no generic "perform action" API
setComposingText / setComposingRegion / finishComposingText❌no marked/composing-text API for extensions
beginBatchEdit / endBatchEdit❌no batch-edit concept
getCurrentEditorInfo / onEditorInfoChange / onSelectionChange❌no EditorInfo descriptor or event-emitter mechanism wired up on the iOS side
hideKeyboard❌no self-dismiss API for third-party keyboard extensions

❌ rows are Android only; the iOS native module's same-named method is a silent no-op (or resolves a safe default, e.g. null/'', for value-returning ones).

sendKeyEvent/performEditorAction cover the cases commitText/deleteSurroundingText don't: some editors (search boxes, single-line forms) respond to a real hardware-style key event or their own IME action instead of inserted text. switchToPreviousInputMethod/hideKeyboard back a "globe"/"hide keyboard" key. getCursorCapsMode lets a keyboard auto-capitalize the next letter the way system keyboards do.

Three constant maps are exported alongside these, so callers don't have to remember Android's raw integer codes:

const KeyEventCodes: { ENTER, DEL, TAB, SPACE, ESCAPE, FORWARD_DEL, DPAD_LEFT, DPAD_RIGHT, DPAD_UP, DPAD_DOWN };
const EditorActions: { UNSPECIFIED, NONE, GO, SEARCH, SEND, NEXT, DONE, PREVIOUS };
const CapsModeRequest: { CHARACTERS, WORDS, SENTENCES };

Settings functions​

Run from the host app's own screen (e.g. an onboarding step in App.tsx), not from inside the keyboard — enabling/switching a keyboard is something only the app the user already has open can prompt them to do.

function openInputMethodSettings(): void;
function showInputMethodPicker(): void;
function isKeyboardEnabled(): Promise<boolean>;
function isKeyboardSelected(): Promise<boolean>;

openInputMethodSettings works on both platforms: Android opens system Settings' keyboard-management screen directly; iOS can only open this app's own Settings page (Apple exposes no deeper deep link), from which the user still navigates to General > Keyboard > Keyboards themselves. showInputMethodPicker/isKeyboardEnabled/isKeyboardSelected are Android only — iOS has no API for a containing app to do either, so these resolve a safe default (false/no-op) there instead of throwing.