How to Add Haptic Feedback and Click Sounds to a React Native Keyboard
A keyboard that only commits the right characters still feels wrong if it doesn't vibrate, click, or auto-capitalize the way the system keyboard does. Those details are small individually, but they're the difference between "a keyboard" and "the keyboard I forgot wasn't the system one."
Haptic feedback on every key press
function performHapticFeedback(): void;
One call, no configuration. On iOS, this silently no-ops until the user has granted "Allow Full Access" — a platform restriction on extensions, not a bug — so don't rely on it as the only signal a key press succeeded.
Click sounds, with named effects
function playClickSound(effect?: string): void;
const SoundEffect = {
STANDARD: 'standard',
SPACEBAR: 'spacebar',
DELETE: 'delete',
RETURN: 'return',
INVALID: 'invalid',
};
<TouchableOpacity
onPress={() => {
playClickSound(SoundEffect.STANDARD);
commitText('a');
}}
>
iOS has exactly one system click sound regardless of which named effect you pass — the effect
argument is accepted but ignored there. Android maps each name to the matching
AudioManager.FX_KEYPRESS_* constant.
Auto-capitalizing like the system keyboard
function getCursorCapsMode(reqModes?: number): Promise<number>;
const CapsModeRequest = {
CHARACTERS: 1 << 0,
WORDS: 1 << 1,
SENTENCES: 1 << 2,
};
useEffect(() => {
getCursorCapsMode(CapsModeRequest.SENTENCES).then((mode) => {
setShift(mode !== 0);
});
}, [cursorPosition]);
This mirrors android.text.TextUtils.CAP_MODE_* — request SENTENCES and you get a non-zero
result exactly when the cursor sits at the start of a sentence, the same signal the system
keyboard uses to auto-capitalize the next letter. On iOS it's an approximation (a heuristic over
documentContextBeforeInput, not Android's exact locale-aware algorithm) but close enough that
users won't notice the difference in normal typing.
Adapting the return key to context
function performEditorAction(actionCode: number): void;
const EditorActions = {
GO: 2, SEARCH: 3, SEND: 4, NEXT: 5, DONE: 6,
};
A search box sets IME_ACTION_SEARCH; a single-line form field often sets IME_ACTION_NEXT.
Reading which one is active (via getCurrentEditorInfo/onEditorInfoChange on Android) lets your
"return" key render "Search" or "Next" instead of a generic newline — and performEditorAction
lets pressing it actually trigger that action instead of inserting \n into a field that doesn't
want one. This is Android-only (no generic "perform action" API exists on iOS), so it's a safe
no-op there — see the feel-and-polish tutorial for wiring all of
this into one component.
Try it yourself
This is a real, working library, not a proof-of-concept — install it and build your own keyboard:
yarn add react-native-keyboard-bridge
