Skip to main content

Swipe-to-Type

Swipe-typing — dragging a finger across letters instead of tapping each one — is exposed as one pure function: keysAlongPath. The library handles the geometry; you handle capturing the touch path and deciding what to do with the result.

Describe your layout as Key/KeyRow data​

Gesture matching works on a small, explicit data shape — not your rendered View tree:

import type { Key, KeyRow } from 'react-native-keyboard-bridge';

function row(letters: string[]): KeyRow {
return {
keys: letters.map((letter) => ({
id: letter,
label: letter,
width: 1, // one "standard key" unit each
action: 'insertChar',
value: letter,
})),
};
}

const ROWS: KeyRow[] = [
row(['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p']),
row(['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l']),
row(['z', 'x', 'c', 'v', 'b', 'n', 'm']),
];

width and the implicit row height are in grid units, not pixels — computeGeometry (used internally by keysAlongPath) lays keys out row-major, left to right, at rowHeight per row (default 1). A row of ten width: 1 keys is 10 units wide; if you render that row across, say, 360 real pixels, each unit is 36px.

Capture the raw touch path​

The library doesn't capture gestures for you — that's a PanResponder job, and it means converting pixel coordinates into the same grid units your Key.width/rowHeight use:

import React, { useRef, useState } from 'react';
import { View, Text, TouchableOpacity, PanResponder, StyleSheet } from 'react-native';
import { commitText, keysAlongPath } from 'react-native-keyboard-bridge';
import type { TouchPoint } from 'react-native-keyboard-bridge';

const KEY_SIZE_PX = 36; // must match your actual rendered key size

export default function KeyboardApp() {
const path = useRef<TouchPoint[]>([]);
const [preview, setPreview] = useState('');

const responder = useRef(
PanResponder.create({
onStartShouldSetPanResponder: () => true,
onMoveShouldSetPanResponder: () => true,
onPanResponderMove: (_, gesture) => {
const point: TouchPoint = {
x: gesture.moveX / KEY_SIZE_PX,
y: gesture.moveY / KEY_SIZE_PX,
};
path.current.push(point);
const visited = keysAlongPath(ROWS, path.current);
setPreview(visited.map((k) => k.value ?? k.label).join(''));
},
onPanResponderRelease: () => {
if (preview.length > 0) {
commitText(preview);
}
path.current = [];
setPreview('');
},
}),
).current;

return (
<View {...responder.panHandlers}>
{/* render ROWS as TouchableOpacity keys, same as the basic keyboard tutorial */}
{preview.length > 0 && (
<View style={styles.previewBar}>
<Text style={styles.previewText}>{preview}</Text>
</View>
)}
</View>
);
}

const styles = StyleSheet.create({
previewBar: { padding: 6, backgroundColor: '#e5e7eb' },
previewText: { fontSize: 16, fontWeight: '600' },
});

keysAlongPath(rows, path, rowHeight?) returns the ordered, de-duplicated sequence of Key objects the path crossed — points outside every key's bounds are ignored, and passing back over the same key without leaving it first doesn't duplicate it in the result. Both computeGeometry and keysAlongPath are pure, synchronous, and have zero React Native dependency, so you can unit test your layout's gesture behavior (e.g. "does this exact path visit h, e, l, l, o in order?") without a simulator or device at all.

This is letters, not words — pair it with prediction​

keysAlongPath gives you the literal keys a finger crossed. A real swipe keyboard then treats that sequence as a fuzzy hint — feeding the joined string as a prefix into a WordPredictor, or scoring dictionary candidates against the visited key sequence to correct for an imprecise swipe — rather than committing the raw joined letters directly the way the minimal example above does. The next section builds exactly that predictor layer on top of this same gesture data.

Next: Word prediction — turn a swiped or typed prefix into ranked suggestions.