<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>react-native-keyboard-bridge Blog</title>
        <link>https://keyboardbridge.github.io/blog</link>
        <description>react-native-keyboard-bridge Blog</description>
        <lastBuildDate>Fri, 18 Sep 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[How to Get Live Reload Working in a React Native Keyboard Extension]]></title>
            <link>https://keyboardbridge.github.io/blog/live-reload-for-keyboard-extensions</link>
            <guid>https://keyboardbridge.github.io/blog/live-reload-for-keyboard-extensions</guid>
            <pubDate>Fri, 18 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Enable Metro Fast Refresh for a React Native custom keyboard on both Android and iOS — no more rebuild-and-reinstall loop every time you change your keyboard component.]]></description>
            <content:encoded><![CDATA[<p>Before this, changing a single line in <code>KeyboardApp.tsx</code> meant a full rebundle and reinstall on
both platforms — no Fast Refresh, no live reload, just the standard edit-rebuild-reinstall loop
every time. It turns out the fix required two completely different investigations, because
Android and iOS started from opposite places.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="android-already-had-this--just-never-wired-up">Android already had this — just never wired up<a href="https://keyboardbridge.github.io/blog/live-reload-for-keyboard-extensions#android-already-had-this--just-never-wired-up" class="hash-link" aria-label="Direct link to Android already had this — just never wired up" title="Direct link to Android already had this — just never wired up" translate="no">​</a></h2>
<p><code>CustomKeyboardService.kt</code> already passes <code>useDevSupport = BuildConfig.DEBUG</code> and
<code>allowPackagerServerAccess = true</code> to <code>ReactHostImpl</code>. Reading <code>ReactHostImpl</code>'s own source
confirmed something surprising: whenever both flags are true, it <em>already</em> pings the packager on
every surface creation and transparently swaps in a Metro-fetched bundle instead of the committed
asset one. This is core upstream React Native behavior — nothing the library needed to add. It
silently wasn't working before only because the dev workflow never had Metro running with <code>adb reverse tcp:8081 tcp:8081</code> set up for the app.</p>
<p>Zero code changes. Just: run <code>npx react-native start</code>, run <code>adb reverse tcp:8081 tcp:8081</code> (or use
<code>react-native run-android</code>, which does it for you), install a debug build, and real Fast Refresh
on save just works.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ios-needed-an-actual-code-change">iOS needed an actual code change<a href="https://keyboardbridge.github.io/blog/live-reload-for-keyboard-extensions#ios-needed-an-actual-code-change" class="hash-link" aria-label="Direct link to iOS needed an actual code change" title="Direct link to iOS needed an actual code change" translate="no">​</a></h2>
<p><code>RNKeyboardBootstrap.swift</code>'s <code>bundleURL()</code> hardcoded the committed <code>main.jsbundle</code> unconditionally
— even in DEBUG builds — because <code>RCTReactNativeFactory</code> has no automatic "check if Metro is up"
fallback the way Android's <code>ReactHostImpl</code> does. The fix mirrors the standard RN iOS app template
exactly:</p>
<div class="language-swift codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-swift codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">override</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">bundleURL</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">URL</span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token directive property directive-name" style="color:#36acaa">#if</span><span class="token directive property" style="color:#36acaa"> DEBUG</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token class-name">RCTBundleURLProvider</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">sharedSettings</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">jsBundleURL</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">forBundleRoot</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string-literal string" style="color:#e3116c">"index"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token directive property directive-name" style="color:#36acaa">#else</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token class-name">Bundle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">for</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">KeyboardReactNativeDelegate</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">url</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">forResource</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string-literal string" style="color:#e3116c">"main"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> withExtension</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string-literal string" style="color:#e3116c">"jsbundle"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token directive property directive-name" style="color:#36acaa">#endif</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span><br></div></code></pre></div></div>
<p>RELEASE builds are completely unaffected — they still load the committed bundle, unchanged.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-one-new-requirement-temporary-network-access">The one new requirement: temporary network access<a href="https://keyboardbridge.github.io/blog/live-reload-for-keyboard-extensions#the-one-new-requirement-temporary-network-access" class="hash-link" aria-label="Direct link to The one new requirement: temporary network access" title="Direct link to The one new requirement: temporary network access" translate="no">​</a></h2>
<p>A DEBUG keyboard extension reaching Metro needs network access, which extensions don't have by
default. Two one-time, reversible toggles:</p>
<ol>
<li class="">Set <code>NSExtension &gt; NSExtensionAttributes &gt; RequestsOpenAccess</code> to <code>true</code> in the extension's
<code>Info.plist</code>.</li>
<li class="">Enable "Allow Full Access" for the keyboard in Settings, once it's installed.</li>
</ol>
<p>Both should flip back to <code>false</code>/off before a release build — <code>RequestsOpenAccess: true</code> is a
real, user-visible permission request with no reason to ship if your keyboard has no other need
for network access.</p>
<p>If Metro isn't running when a DEBUG build launches, there's no fallback to the committed bundle —
same as any standard debug React Native app. The one difference: an extension process has no
<code>UIWindow</code> to present a red error screen in, so the failure can be silent from the UI's
perspective. Check Console.app logs for "Could not connect to development server" if the keyboard
doesn't render.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it-yourself">Try it yourself<a href="https://keyboardbridge.github.io/blog/live-reload-for-keyboard-extensions#try-it-yourself" class="hash-link" aria-label="Direct link to Try it yourself" title="Direct link to Try it yourself" translate="no">​</a></h2>
<p>This is a real, working library, not a proof-of-concept — install it and build your own keyboard:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">yarn add react-native-keyboard-bridge</span><br></div></code></pre></div></div>
<ul>
<li class="">📖 <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/" target="_blank" rel="noopener noreferrer" class="">Full documentation &amp; tutorial</a></li>
<li class="">⭐ <a href="https://github.com/DeveloperRejaul/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Source on GitHub</a></li>
<li class="">📦 <a href="https://www.npmjs.com/package/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Package on npm</a></li>
</ul>]]></content:encoded>
            <category>devex</category>
            <category>react-native</category>
            <category>metro</category>
        </item>
        <item>
            <title><![CDATA[How to Prompt Users to Enable a Custom Keyboard in React Native]]></title>
            <link>https://keyboardbridge.github.io/blog/onboarding-users-to-enable-your-keyboard</link>
            <guid>https://keyboardbridge.github.io/blog/onboarding-users-to-enable-your-keyboard</guid>
            <pubDate>Thu, 10 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Design an onboarding screen that guides users to enable and switch to your custom React Native keyboard on Android and iOS, including a full three-state example.]]></description>
            <content:encoded><![CDATA[<p>Shipping a keyboard is only half the job — a user still has to find Settings, enable it, and
select it before it ever appears. Neither Android nor iOS lets an app skip that flow, so the best
you can do is make it as short as possible from your own app's screen.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-four-settings-functions">The four settings functions<a href="https://keyboardbridge.github.io/blog/onboarding-users-to-enable-your-keyboard#the-four-settings-functions" class="hash-link" aria-label="Direct link to The four settings functions" title="Direct link to The four settings functions" translate="no">​</a></h2>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">openInputMethodSettings</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">showInputMethodPicker</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">isKeyboardEnabled</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">Promise</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">boolean</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">isKeyboardSelected</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">Promise</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">boolean</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span></span><br></div></code></pre></div></div>
<p>These run from the <em>host app's own</em> screen — an onboarding step in <code>App.tsx</code>, typically — never
from inside the keyboard itself. Enabling or switching a keyboard is something only the app the
user already has open in the foreground can prompt them to do.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="android-a-real-three-state-flow">Android: a real three-state flow<a href="https://keyboardbridge.github.io/blog/onboarding-users-to-enable-your-keyboard#android-a-real-three-state-flow" class="hash-link" aria-label="Direct link to Android: a real three-state flow" title="Direct link to Android: a real three-state flow" translate="no">​</a></h2>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">EnableKeyboardScreen</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">enabled</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setEnabled</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">selected</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setSelected</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token function" style="color:#d73a49">useEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token function" style="color:#d73a49">isKeyboardEnabled</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">setEnabled</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token function" style="color:#d73a49">isKeyboardSelected</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">setSelected</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">selected</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">You're all set — this keyboard is active.</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">enabled</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">title</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">Switch to this keyboard</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onPress</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">showInputMethodPicker</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">title</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">Enable keyboard</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onPress</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">openInputMethodSettings</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span><br></div></code></pre></div></div>
<p><code>openInputMethodSettings</code> opens system Settings' keyboard-management screen directly on Android —
the user toggles your keyboard on and returns to your app. <code>showInputMethodPicker</code> then opens the
system's own keyboard-switcher sheet so they can make it active without leaving the app at all.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ios-a-shorter-deep-link-then-manual-navigation">iOS: a shorter deep link, then manual navigation<a href="https://keyboardbridge.github.io/blog/onboarding-users-to-enable-your-keyboard#ios-a-shorter-deep-link-then-manual-navigation" class="hash-link" aria-label="Direct link to iOS: a shorter deep link, then manual navigation" title="Direct link to iOS: a shorter deep link, then manual navigation" translate="no">​</a></h2>
<p><code>openInputMethodSettings</code> still works on iOS, but Apple exposes no deeper deep link than <em>this
app's own Settings page</em> — there's no API to jump straight to General &gt; Keyboard &gt; Keyboards. The
user still navigates the last step themselves. <code>showInputMethodPicker</code>, <code>isKeyboardEnabled</code>, and
<code>isKeyboardSelected</code> have no iOS equivalent at all (no API lets a containing app query or drive
keyboard-picker state), so they resolve a safe default (<code>false</code>/no-op) instead of throwing —
meaning the same <code>EnableKeyboardScreen</code> component above degrades gracefully to just the "Enable
keyboard" button on iOS, with a caption explaining the one extra manual step.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="design-around-the-asymmetry-dont-hide-it">Design around the asymmetry, don't hide it<a href="https://keyboardbridge.github.io/blog/onboarding-users-to-enable-your-keyboard#design-around-the-asymmetry-dont-hide-it" class="hash-link" aria-label="Direct link to Design around the asymmetry, don't hide it" title="Direct link to Design around the asymmetry, don't hide it" translate="no">​</a></h2>
<p>The honest version of this screen tells iOS users explicitly: "tap Enable, then go to General &gt;
Keyboard &gt; Keyboards &gt; [Your App] and turn on Allow Full Access if prompted." Trying to make the
two platforms look identical here usually means one of them silently doesn't work — better to
show each platform's real, shortest path.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it-yourself">Try it yourself<a href="https://keyboardbridge.github.io/blog/onboarding-users-to-enable-your-keyboard#try-it-yourself" class="hash-link" aria-label="Direct link to Try it yourself" title="Direct link to Try it yourself" translate="no">​</a></h2>
<p>This is a real, working library, not a proof-of-concept — install it and build your own keyboard:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">yarn add react-native-keyboard-bridge</span><br></div></code></pre></div></div>
<ul>
<li class="">📖 <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/" target="_blank" rel="noopener noreferrer" class="">Full documentation &amp; tutorial</a></li>
<li class="">⭐ <a href="https://github.com/DeveloperRejaul/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Source on GitHub</a></li>
<li class="">📦 <a href="https://www.npmjs.com/package/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Package on npm</a></li>
</ul>]]></content:encoded>
            <category>ux</category>
            <category>react-native</category>
            <category>keyboard</category>
        </item>
        <item>
            <title><![CDATA[How to Add Haptic Feedback and Click Sounds to a React Native Keyboard]]></title>
            <link>https://keyboardbridge.github.io/blog/haptics-sound-and-feel</link>
            <guid>https://keyboardbridge.github.io/blog/haptics-sound-and-feel</guid>
            <pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Make a custom React Native keyboard feel native with haptic feedback, click sounds, and auto-capitalization — a practical guide with real API examples for both platforms.]]></description>
            <content:encoded><![CDATA[<p>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."</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="haptic-feedback-on-every-key-press">Haptic feedback on every key press<a href="https://keyboardbridge.github.io/blog/haptics-sound-and-feel#haptic-feedback-on-every-key-press" class="hash-link" aria-label="Direct link to Haptic feedback on every key press" title="Direct link to Haptic feedback on every key press" translate="no">​</a></h2>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">performHapticFeedback</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">;</span></span><br></div></code></pre></div></div>
<p>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.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="click-sounds-with-named-effects">Click sounds, with named effects<a href="https://keyboardbridge.github.io/blog/haptics-sound-and-feel#click-sounds-with-named-effects" class="hash-link" aria-label="Direct link to Click sounds, with named effects" title="Direct link to Click sounds, with named effects" translate="no">​</a></h2>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">playClickSound</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">effect</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> SoundEffect </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">STANDARD</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'standard'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">SPACEBAR</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'spacebar'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">DELETE</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'delete'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">RETURN</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'return'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">INVALID</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'invalid'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span></span><br></div></code></pre></div></div>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag" style="color:#00009f"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token tag" style="color:#00009f">  </span><span class="token tag attr-name" style="color:#00a4db">onPress</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token tag script language-javascript" style="color:#00009f">    </span><span class="token tag script language-javascript function" style="color:#d73a49">playClickSound</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript maybe-class-name" style="color:#00009f">SoundEffect</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript constant" style="color:#36acaa">STANDARD</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">;</span><span class="token tag script language-javascript" style="color:#00009f"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token tag script language-javascript" style="color:#00009f">    </span><span class="token tag script language-javascript function" style="color:#d73a49">commitText</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript string" style="color:#e3116c">'a'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">;</span><span class="token tag script language-javascript" style="color:#00009f"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token tag script language-javascript" style="color:#00009f">  </span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token tag" style="color:#00009f"></span><span class="token tag punctuation" style="color:#393A34">&gt;</span></span><br></div></code></pre></div></div>
<p>iOS has exactly one system click sound regardless of which named effect you pass — the <code>effect</code>
argument is accepted but ignored there. Android maps each name to the matching
<code>AudioManager.FX_KEYPRESS_*</code> constant.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="auto-capitalizing-like-the-system-keyboard">Auto-capitalizing like the system keyboard<a href="https://keyboardbridge.github.io/blog/haptics-sound-and-feel#auto-capitalizing-like-the-system-keyboard" class="hash-link" aria-label="Direct link to Auto-capitalizing like the system keyboard" title="Direct link to Auto-capitalizing like the system keyboard" translate="no">​</a></h2>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getCursorCapsMode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">reqModes</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">Promise</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">number</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> CapsModeRequest </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">CHARACTERS</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">WORDS</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">SENTENCES</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span></span><br></div></code></pre></div></div>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token function" style="color:#d73a49">useEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token function" style="color:#d73a49">getCursorCapsMode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token maybe-class-name">CapsModeRequest</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">SENTENCES</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token function" style="color:#d73a49">setShift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mode </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">cursorPosition</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span></span><br></div></code></pre></div></div>
<p>This mirrors <code>android.text.TextUtils.CAP_MODE_*</code> — request <code>SENTENCES</code> 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
<code>documentContextBeforeInput</code>, not Android's exact locale-aware algorithm) but close enough that
users won't notice the difference in normal typing.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="adapting-the-return-key-to-context">Adapting the return key to context<a href="https://keyboardbridge.github.io/blog/haptics-sound-and-feel#adapting-the-return-key-to-context" class="hash-link" aria-label="Direct link to Adapting the return key to context" title="Direct link to Adapting the return key to context" translate="no">​</a></h2>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">performEditorAction</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">actionCode</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> EditorActions </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">GO</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">SEARCH</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">SEND</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">NEXT</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">DONE</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">6</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span></span><br></div></code></pre></div></div>
<p>A search box sets <code>IME_ACTION_SEARCH</code>; a single-line form field often sets <code>IME_ACTION_NEXT</code>.
Reading which one is active (via <code>getCurrentEditorInfo</code>/<code>onEditorInfoChange</code> on Android) lets your
"return" key render "Search" or "Next" instead of a generic newline — and <code>performEditorAction</code>
lets pressing it actually trigger that action instead of inserting <code>\n</code> 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 <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/tutorial/feel-and-polish" target="_blank" rel="noopener noreferrer" class="">feel-and-polish tutorial</a> for wiring all of
this into one component.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it-yourself">Try it yourself<a href="https://keyboardbridge.github.io/blog/haptics-sound-and-feel#try-it-yourself" class="hash-link" aria-label="Direct link to Try it yourself" title="Direct link to Try it yourself" translate="no">​</a></h2>
<p>This is a real, working library, not a proof-of-concept — install it and build your own keyboard:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">yarn add react-native-keyboard-bridge</span><br></div></code></pre></div></div>
<ul>
<li class="">📖 <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/" target="_blank" rel="noopener noreferrer" class="">Full documentation &amp; tutorial</a></li>
<li class="">⭐ <a href="https://github.com/DeveloperRejaul/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Source on GitHub</a></li>
<li class="">📦 <a href="https://www.npmjs.com/package/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Package on npm</a></li>
</ul>]]></content:encoded>
            <category>ux</category>
            <category>react-native</category>
            <category>keyboard</category>
        </item>
        <item>
            <title><![CDATA[How to Package a React Native Library with Native Android and iOS Modules]]></title>
            <link>https://keyboardbridge.github.io/blog/one-package-to-rule-them-all</link>
            <guid>https://keyboardbridge.github.io/blog/one-package-to-rule-them-all</guid>
            <pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[How react-native-keyboard-bridge consolidated four separate packages into a single npm install — real lessons on packaging native modules, autolinking, and monorepo layout.]]></description>
            <content:encoded><![CDATA[<p>Early on, this library was four separate workspace packages: a <code>core</code> package (gestures/
prediction/layout types), a raw Gradle module wired in through a hand-edited <code>settings.gradle</code>, a
Swift-sources-plus-Ruby-script package hardcoded to one example project's paths, and the actual
published <code>react-native-keyboard-bridge</code> npm package. A real external consumer would have needed
two npm installs, a git submodule or hand-copy for the native folders, and manual edits across
<code>settings.gradle</code>, <code>app/build.gradle</code>, <code>MainApplication.kt</code>, and <code>AndroidManifest.xml</code>.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-end-goal-was-one-command">The end goal was one command<a href="https://keyboardbridge.github.io/blog/one-package-to-rule-them-all#the-end-goal-was-one-command" class="hash-link" aria-label="Direct link to The end goal was one command" title="Direct link to The end goal was one command" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">yarn add react-native-keyboard-bridge</span><br></div></code></pre></div></div>
<p>Everything folds into that single package now: the JS bridge/settings functions, gestures,
layouts, word prediction, the Android native module (<code>android/</code>), the iOS native module and setup
CLI (<code>ios/</code>, <code>bin/</code>). Two real bugs got fixed in the process of merging, not just files moved
around:</p>
<ol>
<li class="">Android's <code>&lt;service&gt;</code> declaration for <code>CustomKeyboardService</code> used to live only in the example
app's own manifest, hardcoded with that app's own package name. It now lives in the library's
own manifest, using a Gradle placeholder resolved to <em>the consuming app's</em> applicationId at
merge time — verified by inspecting the actual merged manifest output.</li>
<li class="">The host-app-facing native module needed a manual <code>MainApplication.kt</code> line before; it's now
declared as this dependency's autolinked <code>packageInstance</code> in <code>react-native.config.js</code>.</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ios-still-cant-be-a-zero-step-install--and-thats-fine">iOS still can't be a zero-step install — and that's fine<a href="https://keyboardbridge.github.io/blog/one-package-to-rule-them-all#ios-still-cant-be-a-zero-step-install--and-thats-fine" class="hash-link" aria-label="Direct link to iOS still can't be a zero-step install — and that's fine" title="Direct link to iOS still can't be a zero-step install — and that's fine" translate="no">​</a></h2>
<p>This is an Apple platform constraint, not a gap in the library: a custom keyboard requires its own
Xcode App Extension target, and no CocoaPod or npm install can fabricate a new Xcode target from
outside Xcode's own project file format. <code>setup_xcode_targets.rb</code> handles the one step that
genuinely can't be automated away — discovering the consumer's own <code>.xcodeproj</code>, its app target,
and its bundle identifier, all without a single hardcoded path to any specific project name.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-second-flattening-later">A second flattening, later<a href="https://keyboardbridge.github.io/blog/one-package-to-rule-them-all#a-second-flattening-later" class="hash-link" aria-label="Direct link to A second flattening, later" title="Direct link to A second flattening, later" translate="no">​</a></h2>
<p>Even after the four-package merge, the published package still lived nested two levels deep —
<code>packages/react-native/</code>, with its own inner <code>src/</code> folder for pure TypeScript. Since there's only
ever been one package since the consolidation, that nesting stopped serving a purpose. It's since
been flattened to <code>src/</code> at the repo root, with the inner TypeScript folder renamed to <code>core/</code> — a
purely mechanical rename, verified with a full rebuild on both platforms, that finally makes the
repo's layout match what a "one package" library should look like on disk, not just in
<code>package.json</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it-yourself">Try it yourself<a href="https://keyboardbridge.github.io/blog/one-package-to-rule-them-all#try-it-yourself" class="hash-link" aria-label="Direct link to Try it yourself" title="Direct link to Try it yourself" translate="no">​</a></h2>
<p>This is a real, working library, not a proof-of-concept — install it and build your own keyboard:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">yarn add react-native-keyboard-bridge</span><br></div></code></pre></div></div>
<ul>
<li class="">📖 <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/" target="_blank" rel="noopener noreferrer" class="">Full documentation &amp; tutorial</a></li>
<li class="">⭐ <a href="https://github.com/DeveloperRejaul/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Source on GitHub</a></li>
<li class="">📦 <a href="https://www.npmjs.com/package/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Package on npm</a></li>
</ul>]]></content:encoded>
            <category>architecture</category>
            <category>monorepo</category>
            <category>react-native</category>
        </item>
        <item>
            <title><![CDATA[What Can (and Can't) an iOS Custom Keyboard Extension Do?]]></title>
            <link>https://keyboardbridge.github.io/blog/ios-custom-keyboard-constraints</link>
            <guid>https://keyboardbridge.github.io/blog/ios-custom-keyboard-constraints</guid>
            <pubDate>Mon, 10 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A complete guide to iOS Custom Keyboard Extension limitations — what UITextDocumentProxy allows, why Full Access is required for network access, and what Apple simply doesn't permit.]]></description>
            <content:encoded><![CDATA[<p>Apple's Custom Keyboard Extension API is deliberately narrow — narrower than most developers
expect coming from Android's <code>InputConnection</code>. Knowing the actual boundary up front saves you
from designing a feature the platform will simply never let you ship.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="uitextdocumentproxy-is-the-entire-surface"><code>UITextDocumentProxy</code> is the entire surface<a href="https://keyboardbridge.github.io/blog/ios-custom-keyboard-constraints#uitextdocumentproxy-is-the-entire-surface" class="hash-link" aria-label="Direct link to uitextdocumentproxy-is-the-entire-surface" title="Direct link to uitextdocumentproxy-is-the-entire-surface" translate="no">​</a></h2>
<p>Everything a keyboard extension can do to the host text field goes through
<code>UITextDocumentProxy</code>/<code>UIInputViewController</code> — there's no lower-level access, no
<code>InputConnection</code>-equivalent with dozens of methods. The
<a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/api/bridge-functions" target="_blank" rel="noopener noreferrer" class="">bridge-function parity table</a> exists precisely because this surface
is so much smaller than Android's:</p>
<ul>
<li class=""><strong>Fully supported</strong>: inserting text, reading text before/after the cursor, reading the current
selection, advancing to the next input mode.</li>
<li class=""><strong>Approximated</strong>: deleting <em>after</em> the cursor (no forward-delete API — <code>deleteSurroundingText</code>'s
<code>after</code> argument is silently ignored on iOS), "switch to previous input method" (iOS has no
distinct "previous," so it calls the same "next" API), cursor caps-mode (a heuristic over
<code>documentContextBeforeInput</code>, not Android's exact locale-aware algorithm).</li>
<li class=""><strong>Not possible at all</strong>: absolute-offset selection, key-event injection, generic "editor action"
dispatch, marked/composing text, batch edits, or a keyboard dismissing itself.</li>
</ul>
<p>None of these iOS-only gaps throw. Every function the library exposes is defined on both
platforms; the ones with no iOS equivalent are safe no-ops (or resolve a safe default value)
specifically so a shared <code>KeyboardApp.tsx</code> never needs an <code>if (Platform.OS === ...)</code> branch.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="full-access-is-an-explicit-visible-user-choice">Full Access is an explicit, visible user choice<a href="https://keyboardbridge.github.io/blog/ios-custom-keyboard-constraints#full-access-is-an-explicit-visible-user-choice" class="hash-link" aria-label="Direct link to Full Access is an explicit, visible user choice" title="Direct link to Full Access is an explicit, visible user choice" translate="no">​</a></h2>
<p>Any network request from inside the extension process requires the user to grant "Allow Full
Access" in Settings — and that toggle only appears at all if the extension's <code>Info.plist</code> sets
<code>RequestsOpenAccess</code> to <code>true</code>. There's no way around this for anything that needs the network,
including connecting to a Metro dev server during development.</p>
<p>This library ships <code>RequestsOpenAccess: false</code> by default in the scaffolded <code>Info.plist</code> — a
production keyboard that has no other reason to need network access should ship with no reason to
prompt the user for it. Development is the one carve-out: flip it to <code>true</code> locally to get
<a href="https://developerrejaul.github.io/react-native-keyboard-bridge/blog/live-reload-for-keyboard-extensions" target="_blank" rel="noopener noreferrer" class="">Metro live reload</a>, and flip it back before a release
build.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="enabling-a-keyboard-is-always-the-users-decision">Enabling a keyboard is always the user's decision<a href="https://keyboardbridge.github.io/blog/ios-custom-keyboard-constraints#enabling-a-keyboard-is-always-the-users-decision" class="hash-link" aria-label="Direct link to Enabling a keyboard is always the user's decision" title="Direct link to Enabling a keyboard is always the user's decision" translate="no">​</a></h2>
<p>Neither platform lets an app silently register itself as active — <code>openInputMethodSettings</code> opens
this app's own Settings page on iOS (Apple exposes no deeper deep link than that), from which the
user still navigates to General &gt; Keyboard &gt; Keyboards themselves. There's no API for a containing
app to enable, switch to, or query the enabled/selected state of a keyboard on iOS the way Android
allows — see the <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/tutorial/settings-screen" target="_blank" rel="noopener noreferrer" class="">settings screen tutorial</a> for how to design an
onboarding flow around that asymmetry instead of fighting it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it-yourself">Try it yourself<a href="https://keyboardbridge.github.io/blog/ios-custom-keyboard-constraints#try-it-yourself" class="hash-link" aria-label="Direct link to Try it yourself" title="Direct link to Try it yourself" translate="no">​</a></h2>
<p>This is a real, working library, not a proof-of-concept — install it and build your own keyboard:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">yarn add react-native-keyboard-bridge</span><br></div></code></pre></div></div>
<ul>
<li class="">📖 <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/" target="_blank" rel="noopener noreferrer" class="">Full documentation &amp; tutorial</a></li>
<li class="">⭐ <a href="https://github.com/DeveloperRejaul/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Source on GitHub</a></li>
<li class="">📦 <a href="https://www.npmjs.com/package/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Package on npm</a></li>
</ul>]]></content:encoded>
            <category>ios</category>
            <category>platform</category>
            <category>keyboard</category>
        </item>
        <item>
            <title><![CDATA[How Does an Android IME Work? Hosting React Native Inside InputMethodService]]></title>
            <link>https://keyboardbridge.github.io/blog/android-ime-architecture</link>
            <guid>https://keyboardbridge.github.io/blog/android-ime-architecture</guid>
            <pubDate>Thu, 30 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A deep dive into how react-native-keyboard-bridge hosts a real, standalone React Native ReactHost inside an Android InputMethodService — no classic bridge, no Activity required.]]></description>
            <content:encoded><![CDATA[<p>Android's <code>InputMethodService</code> has a much larger memory budget than iOS's extension model, which
is exactly why the Android side of this library could go straight to "host real React Native" with
none of the multi-generation caution iOS needed.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-not-the-classic-bridge">Why not the classic bridge?<a href="https://keyboardbridge.github.io/blog/android-ime-architecture#why-not-the-classic-bridge" class="hash-link" aria-label="Direct link to Why not the classic bridge?" title="Direct link to Why not the classic bridge?" translate="no">​</a></h2>
<p>The obvious first approach — <code>ReactInstanceManager</code>, the classic (pre-New-Architecture) bridge —
turned out to be a dead end: current React Native versions unconditionally throw when you try to
construct one outside of an <code>Activity</code>-hosted flow. An <code>InputMethodService</code> is not an <code>Activity</code>.</p>
<p>The validated replacement is <code>ReactHostImpl</code> + <code>ReactSurface</code> — bridgeless, New Architecture,
Fabric — and critically, <code>com.facebook.react.runtime.ReactSurfaceView</code> is a plain <code>View</code> with no
<code>Activity</code> dependency, confirmed by reading the framework source directly rather than assuming.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-shape-of-it">The shape of it<a href="https://keyboardbridge.github.io/blog/android-ime-architecture#the-shape-of-it" class="hash-link" aria-label="Direct link to The shape of it" title="Direct link to The shape of it" translate="no">​</a></h2>
<div class="language-kotlin codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-kotlin codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> CustomKeyboardService </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">InputMethodService</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> DefaultHardwareBackBtnHandler </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> reactHost</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ReactHost</span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">override</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">fun</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onCreate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">super</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">onCreate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    reactHost </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">buildReactHost</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">also</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> it</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">start</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">override</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">fun</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onCreateInputView</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> View </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">val</span><span class="token plain"> surface </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> reactHost</span><span class="token operator" style="color:#393A34">!!</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">createSurface</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string-literal singleline string" style="color:#e3116c">"KeyboardApp"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Bundle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    surface</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">start</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> surface</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">view </span><span class="token operator" style="color:#393A34">?:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">View</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span><br></div></code></pre></div></div>
<p><code>buildReactHost()</code> wires a <code>DefaultReactHostDelegate</code> with <code>KeyboardBridgeModule</code> (the native
counterpart to the JS bridge functions) in its package list, and a Hermes <code>JSRuntimeFactory</code>. The
IME owns its own <code>ReactHost</code> — not a shared one with the containing app — so its lifecycle
(<code>onStartInputView</code>/<code>onFinishInputView</code>) maps directly onto <code>ReactHost.onHostResume</code>/
<code>onHostPause</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="zero-manual-android-wiring-on-purpose">Zero manual Android wiring, on purpose<a href="https://keyboardbridge.github.io/blog/android-ime-architecture#zero-manual-android-wiring-on-purpose" class="hash-link" aria-label="Direct link to Zero manual Android wiring, on purpose" title="Direct link to Zero manual Android wiring, on purpose" translate="no">​</a></h2>
<p>Two real integration bugs got fixed while building this, not just moved around:</p>
<ol>
<li class=""><code>CustomKeyboardService</code>'s <code>&lt;service&gt;</code> declaration lives in the <em>library's own</em>
<code>AndroidManifest.xml</code>, using the <code>${applicationId}.MainActivity</code> Gradle placeholder — it merges
into your app's manifest automatically. No manual manifest edit.</li>
<li class=""><code>KeyboardSettingsModule</code> (the host-app-facing native module — <code>openInputMethodSettings</code> and
friends) is declared as this dependency's autolinked <code>packageInstance</code> in
<code>react-native.config.js</code>. No manual <code>MainApplication.kt</code> edit.</li>
</ol>
<p>Autolinking only supports one auto-instantiated package per dependency, which is exactly why the
IME-only <code>KeyboardBridgeModule</code> is <em>not</em> autolinked the same way — <code>CustomKeyboardService</code>
constructs its own standalone <code>ReactHost</code> directly, and the host app's own <code>ReactHost</code> should never
see it. Two native modules, two very different registration paths, by design.</p>
<p>The only things Android still asks you to supply are the two resources that are legitimately
app-specific: <code>res/xml/method.xml</code> (your keyboard's language subtypes) and
<code>res/values/strings.xml</code>'s <code>keyboard_service_label</code> — every app names its own keyboard.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it-yourself">Try it yourself<a href="https://keyboardbridge.github.io/blog/android-ime-architecture#try-it-yourself" class="hash-link" aria-label="Direct link to Try it yourself" title="Direct link to Try it yourself" translate="no">​</a></h2>
<p>This is a real, working library, not a proof-of-concept — install it and build your own keyboard:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">yarn add react-native-keyboard-bridge</span><br></div></code></pre></div></div>
<ul>
<li class="">📖 <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/" target="_blank" rel="noopener noreferrer" class="">Full documentation &amp; tutorial</a></li>
<li class="">⭐ <a href="https://github.com/DeveloperRejaul/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Source on GitHub</a></li>
<li class="">📦 <a href="https://www.npmjs.com/package/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Package on npm</a></li>
</ul>]]></content:encoded>
            <category>android</category>
            <category>architecture</category>
            <category>react-native</category>
        </item>
        <item>
            <title><![CDATA[How to Add Word Prediction to a React Native Keyboard]]></title>
            <link>https://keyboardbridge.github.io/blog/word-prediction-in-50-lines</link>
            <guid>https://keyboardbridge.github.io/blog/word-prediction-in-50-lines</guid>
            <pubDate>Mon, 20 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Add word prediction and autocomplete suggestions to a custom React Native keyboard using the pluggable WordPredictor interface — includes a full suggestion-bar example.]]></description>
            <content:encoded><![CDATA[<p>Word prediction doesn't need to be a black box. The library exposes it as one interface —
<code>WordPredictor</code> — with a minimal built-in implementation you can use as-is or replace entirely.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-interface">The interface<a href="https://keyboardbridge.github.io/blog/word-prediction-in-50-lines#the-interface" class="hash-link" aria-label="Direct link to The interface" title="Direct link to The interface" translate="no">​</a></h2>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">WordPredictor</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token function" style="color:#d73a49">suggest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">prefix</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> options</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> SuggestOptions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">SuggestOptions</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  limit</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// default 3</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span><br></div></code></pre></div></div>
<p>That's the entire contract: given what's been typed so far, return candidate completions. Nothing
in the bridge or the UI layer cares how <code>suggest</code> is implemented — frequency-weighted, ML-backed,
server-fetched, whatever your app needs.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-built-in-default">The built-in default<a href="https://keyboardbridge.github.io/blog/word-prediction-in-50-lines#the-built-in-default" class="hash-link" aria-label="Direct link to The built-in default" title="Direct link to The built-in default" translate="no">​</a></h2>
<p><code>StaticDictionaryPredictor</code> is deliberately small: an in-memory word list, case-insensitive prefix
match, ranked shortest-then-alphabetical.</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> predictor </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">StaticDictionaryPredictor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'hello'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'help'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'helm'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'held'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">predictor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">suggest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'hel'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// ['held', 'help', 'helm'] — 'hello' cut off by the default limit of 3</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">predictor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">suggest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'hel'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> limit</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// all four, same ranking</span></span><br></div></code></pre></div></div>
<p>It's meant as a starting point and a reference implementation, not the ceiling of what's possible
— swap it for anything that satisfies <code>WordPredictor</code> once you need frequency weighting or a
larger vocabulary.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="wiring-it-into-a-keyboard">Wiring it into a keyboard<a href="https://keyboardbridge.github.io/blog/word-prediction-in-50-lines#wiring-it-into-a-keyboard" class="hash-link" aria-label="Direct link to Wiring it into a keyboard" title="Direct link to Wiring it into a keyboard" translate="no">​</a></h2>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> predictor </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useMemo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">StaticDictionaryPredictor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">WORDS</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setCurrent</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">''</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> suggestions </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> predictor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">suggest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">press</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">letter</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token function" style="color:#d73a49">commitText</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">letter</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token function" style="color:#d73a49">setCurrent</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">c</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> letter</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">acceptSuggestion</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">word</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token function" style="color:#d73a49">deleteSurroundingText</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token function" style="color:#d73a49">commitText</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">word </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">' '</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token function" style="color:#d73a49">setCurrent</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">''</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span><br></div></code></pre></div></div>
<p>The pattern: track the in-progress word locally (<code>current</code>), show <code>suggestions</code> in a bar above the
keys, and on tap, delete exactly what's been typed so far (<code>current.length</code> characters back) and
commit the full word instead. <code>current</code> resets on space, punctuation, or a suggestion tap — same
as any predictive keyboard's word-boundary handling.</p>
<p>This composes with everything else in the library: run it against the sequence
<a href="https://developerrejaul.github.io/react-native-keyboard-bridge/blog/swipe-to-type" target="_blank" rel="noopener noreferrer" class=""><code>keysAlongPath</code></a> returns from a swipe gesture, or against plain typed input
from tap-based keys. See the <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/tutorial/word-prediction" target="_blank" rel="noopener noreferrer" class="">word prediction tutorial</a> for the
complete suggestion-bar component.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it-yourself">Try it yourself<a href="https://keyboardbridge.github.io/blog/word-prediction-in-50-lines#try-it-yourself" class="hash-link" aria-label="Direct link to Try it yourself" title="Direct link to Try it yourself" translate="no">​</a></h2>
<p>This is a real, working library, not a proof-of-concept — install it and build your own keyboard:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">yarn add react-native-keyboard-bridge</span><br></div></code></pre></div></div>
<ul>
<li class="">📖 <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/" target="_blank" rel="noopener noreferrer" class="">Full documentation &amp; tutorial</a></li>
<li class="">⭐ <a href="https://github.com/DeveloperRejaul/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Source on GitHub</a></li>
<li class="">📦 <a href="https://www.npmjs.com/package/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Package on npm</a></li>
</ul>]]></content:encoded>
            <category>prediction</category>
            <category>react-native</category>
            <category>keyboard</category>
        </item>
        <item>
            <title><![CDATA[How to Add Swipe-to-Type (Gesture Typing) to a React Native Keyboard]]></title>
            <link>https://keyboardbridge.github.io/blog/swipe-to-type</link>
            <guid>https://keyboardbridge.github.io/blog/swipe-to-type</guid>
            <pubDate>Fri, 10 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A step-by-step guide to implementing swipe-to-type gesture typing in a React Native custom keyboard using keysAlongPath and PanResponder, with full working code.]]></description>
            <content:encoded><![CDATA[<p>Swipe-typing (dragging a finger across letters instead of tapping each one) looks like a hard
geometry problem, and it's easy to over-engineer. The library reduces it to one pure function:
<code>keysAlongPath</code>.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-data-shape">The data shape<a href="https://keyboardbridge.github.io/blog/swipe-to-type#the-data-shape" class="hash-link" aria-label="Direct link to The data shape" title="Direct link to The data shape" translate="no">​</a></h2>
<p>Gesture matching works on the same <code>Key</code>/<code>KeyRow</code> shape used for layout — no separate schema:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">Key</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  width</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// in "standard key" units</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  action</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> KeyAction</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  value</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">KeyRow</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  keys</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Key</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span><br></div></code></pre></div></div>
<p><code>computeGeometry(rows, rowHeight)</code> lays these out on a grid (row-major, left to right) in the same
units as <code>width</code>/<code>rowHeight</code> — not pixels. <code>keysAlongPath(rows, path)</code> uses that geometry
internally and returns the ordered, de-duplicated sequence of keys a raw touch path crossed:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">keysAlongPath</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rows</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> KeyRow</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> path</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> TouchPoint</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> rowHeight </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Key</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">TouchPoint</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> x</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> y</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span></span><br></div></code></pre></div></div>
<p>Both are pure, synchronous, and have zero React Native dependency — they're plain TypeScript, so
you can unit test your layout's gesture behavior without a simulator.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="wiring-it-to-a-real-gesture">Wiring it to a real gesture<a href="https://keyboardbridge.github.io/blog/swipe-to-type#wiring-it-to-a-real-gesture" class="hash-link" aria-label="Direct link to Wiring it to a real gesture" title="Direct link to Wiring it to a real gesture" translate="no">​</a></h2>
<p>The one thing the library doesn't do for you is capture the raw touch path — that's a
<code>PanResponder</code> (or <code>react-native-gesture-handler</code>) concern, and it means converting pixel
coordinates into the same grid units your <code>Key.width</code>/<code>rowHeight</code> use:</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">KEY_SIZE_PX</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">36</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> path </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">useRef</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">TouchPoint</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">[</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">]</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> responder </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useRef</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token maybe-class-name">PanResponder</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token function-variable function" style="color:#d73a49">onStartShouldSetPanResponder</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token function-variable function" style="color:#d73a49">onPanResponderMove</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> gesture</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">current</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        x</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> gesture</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">moveX</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">KEY_SIZE_PX</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        y</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> gesture</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">moveY</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">KEY_SIZE_PX</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token function-variable function" style="color:#d73a49">onPanResponderRelease</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> visited </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">keysAlongPath</span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">ROWS</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">current</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> word </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> visited</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">k</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> k</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">value</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">??</span><span class="token plain"> k</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">label</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">''</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token function" style="color:#d73a49">commitText</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">word</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">current</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">current</span><span class="token punctuation" style="color:#393A34">;</span></span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-dictionary-correction-fits-in">Where dictionary correction fits in<a href="https://keyboardbridge.github.io/blog/swipe-to-type#where-dictionary-correction-fits-in" class="hash-link" aria-label="Direct link to Where dictionary correction fits in" title="Direct link to Where dictionary correction fits in" translate="no">​</a></h2>
<p><code>keysAlongPath</code> gives you the literal letters a finger crossed — real swipe keyboards then run
that sequence (or, more precisely, the <em>shape</em> of the path) against a dictionary to correct for
imprecise swipes. That's exactly where <code>WordPredictor</code> composes with this: treat the joined
letters as a prefix, or score dictionary candidates against the visited key sequence, and offer the
result as a suggestion rather than committing directly. See
<a href="https://developerrejaul.github.io/react-native-keyboard-bridge/blog/word-prediction-in-50-lines" target="_blank" rel="noopener noreferrer" class="">Word Prediction in ~50 Lines</a> for the predictor side, and the
<a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/tutorial/swipe-typing" target="_blank" rel="noopener noreferrer" class="">swipe-typing tutorial</a> for the full gesture-to-commit flow.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it-yourself">Try it yourself<a href="https://keyboardbridge.github.io/blog/swipe-to-type#try-it-yourself" class="hash-link" aria-label="Direct link to Try it yourself" title="Direct link to Try it yourself" translate="no">​</a></h2>
<p>This is a real, working library, not a proof-of-concept — install it and build your own keyboard:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">yarn add react-native-keyboard-bridge</span><br></div></code></pre></div></div>
<ul>
<li class="">📖 <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/" target="_blank" rel="noopener noreferrer" class="">Full documentation &amp; tutorial</a></li>
<li class="">⭐ <a href="https://github.com/DeveloperRejaul/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Source on GitHub</a></li>
<li class="">📦 <a href="https://www.npmjs.com/package/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Package on npm</a></li>
</ul>]]></content:encoded>
            <category>gestures</category>
            <category>react-native</category>
            <category>keyboard</category>
        </item>
        <item>
            <title><![CDATA[How to Support Multiple Languages in a React Native Keyboard (Bangla, Arabic, CJK & More)]]></title>
            <link>https://keyboardbridge.github.io/blog/any-language-any-script</link>
            <guid>https://keyboardbridge.github.io/blog/any-language-any-script</guid>
            <pubDate>Wed, 01 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to build a multi-language custom keyboard in React Native that supports Bangla, Arabic, Devanagari, CJK, and right-to-left scripts — with real Unicode, not transliteration.]]></description>
            <content:encoded><![CDATA[<p>A huge share of "custom keyboard" tutorials quietly assume English. The layout is QWERTY, the
examples commit ASCII, and anything beyond Latin script is left as "an exercise for the reader."
That's backwards for a huge portion of the world's keyboard users.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-library-makes-no-assumption-about-script">The library makes no assumption about script<a href="https://keyboardbridge.github.io/blog/any-language-any-script#the-library-makes-no-assumption-about-script" class="hash-link" aria-label="Direct link to The library makes no assumption about script" title="Direct link to The library makes no assumption about script" translate="no">​</a></h2>
<p><code>commitText</code> takes a plain Unicode string:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">commitText</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">text</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">;</span></span><br></div></code></pre></div></div>
<p>Not a character code, not an ASCII byte, not a Latin-alphabet-shaped enum. Whatever string you
pass — <code>'a'</code>, <code>'অ'</code>, <code>'ا'</code>, <code>'あ'</code>, <code>'的'</code> — gets inserted at the cursor exactly the same way. There
is no script whitelist anywhere in the bridge.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-bangla-row-is-exactly-as-valid-as-a-qwerty-row">A Bangla row is exactly as valid as a QWERTY row<a href="https://keyboardbridge.github.io/blog/any-language-any-script#a-bangla-row-is-exactly-as-valid-as-a-qwerty-row" class="hash-link" aria-label="Direct link to A Bangla row is exactly as valid as a QWERTY row" title="Direct link to A Bangla row is exactly as valid as a QWERTY row" translate="no">​</a></h2>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">BANGLA_ROW_1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'ঙ'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'অ'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'আ'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'ই'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'ঈ'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'উ'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'ঊ'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'ঋ'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'এ'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'ঐ'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">View</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">style</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">styles</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">row</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token constant" style="color:#36acaa">BANGLA_ROW_1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">letter</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">key</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">letter</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onPress</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript function" style="color:#d73a49">commitText</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript" style="color:#00009f">letter</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">style</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">styles</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">key</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">letter</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">View</span><span class="token tag punctuation" style="color:#393A34">&gt;</span></span><br></div></code></pre></div></div>
<p>No special-casing, no separate rendering path, no "non-Latin mode" flag threading through the
component tree. It's the same <code>commitText(letter)</code> call as any other key.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="right-to-left-scripts">Right-to-left scripts<a href="https://keyboardbridge.github.io/blog/any-language-any-script#right-to-left-scripts" class="hash-link" aria-label="Direct link to Right-to-left scripts" title="Direct link to Right-to-left scripts" translate="no">​</a></h2>
<p>Arabic keys work identically:</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onPress</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript function" style="color:#d73a49">commitText</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript string" style="color:#e3116c">'ا'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">  </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">style</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">styles</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">key</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">ا</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag punctuation" style="color:#393A34">&gt;</span></span><br></div></code></pre></div></div>
<p>The <em>keyboard UI itself</em> rendering right-to-left (row order, key alignment) is a React Native
layout concern you control with <code>flexDirection</code> and <code>I18nManager</code>, exactly like any other RN
screen — the library doesn't need to know about text direction at all, because it never
interprets the string, it only inserts it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="multiple-layouts-one-keyboard">Multiple layouts, one keyboard<a href="https://keyboardbridge.github.io/blog/any-language-any-script#multiple-layouts-one-keyboard" class="hash-link" aria-label="Direct link to Multiple layouts, one keyboard" title="Direct link to Multiple layouts, one keyboard" translate="no">​</a></h2>
<p>The natural next step is a language switch key:</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">language</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setLanguage</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">useState</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name string" style="color:#e3116c">'en'</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name operator" style="color:#393A34">|</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name string" style="color:#e3116c">'bn'</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'en'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> rows </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> language </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'en'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">ENGLISH_ROWS</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">BANGLA_ROWS</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onPress</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript function" style="color:#d73a49">setLanguage</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript" style="color:#00009f">l</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript" style="color:#00009f">l </span><span class="token tag script language-javascript operator" style="color:#393A34">===</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'en'</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript operator" style="color:#393A34">?</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'bn'</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'en'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">  </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">🌐</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag punctuation" style="color:#393A34">&gt;</span></span><br></div></code></pre></div></div>
<p>This is <em>in-app</em> layout switching — a <code>useState</code> toggle that swaps which row data you render. It's
a different concern from <code>switchToNextInputMethod</code>, which asks the OS to switch to a <em>different
installed keyboard entirely</em>. Most bilingual keyboards want the former: one installed keyboard,
two (or more) layouts, one language-switch key. See the
<a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/tutorial/multi-language" target="_blank" rel="noopener noreferrer" class="">multi-language tutorial</a> for the complete bilingual example.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="frequently-asked-questions">Frequently asked questions<a href="https://keyboardbridge.github.io/blog/any-language-any-script#frequently-asked-questions" class="hash-link" aria-label="Direct link to Frequently asked questions" title="Direct link to Frequently asked questions" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="can-a-react-native-keyboard-support-non-english-languages-like-bangla-or-arabic">Can a React Native keyboard support non-English languages like Bangla or Arabic?<a href="https://keyboardbridge.github.io/blog/any-language-any-script#can-a-react-native-keyboard-support-non-english-languages-like-bangla-or-arabic" class="hash-link" aria-label="Direct link to Can a React Native keyboard support non-English languages like Bangla or Arabic?" title="Direct link to Can a React Native keyboard support non-English languages like Bangla or Arabic?" translate="no">​</a></h3>
<p>Yes. <code>commitText</code> takes a plain Unicode string with no script restriction — Bangla, Arabic,
Devanagari, CJK, Cyrillic, and any other script work identically to English, with no separate API
or "non-Latin mode."</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-do-i-switch-between-languages-inside-one-keyboard">How do I switch between languages inside one keyboard?<a href="https://keyboardbridge.github.io/blog/any-language-any-script#how-do-i-switch-between-languages-inside-one-keyboard" class="hash-link" aria-label="Direct link to How do I switch between languages inside one keyboard?" title="Direct link to How do I switch between languages inside one keyboard?" translate="no">​</a></h3>
<p>Use local <code>useState</code> to track the active language and swap which row of key data you render — a
<code>🌐</code> key that toggles state, not a call into the native bridge. This keeps multiple layouts inside
one single installed keyboard app.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="does-this-support-right-to-left-rtl-languages">Does this support right-to-left (RTL) languages?<a href="https://keyboardbridge.github.io/blog/any-language-any-script#does-this-support-right-to-left-rtl-languages" class="hash-link" aria-label="Direct link to Does this support right-to-left (RTL) languages?" title="Direct link to Does this support right-to-left (RTL) languages?" translate="no">​</a></h3>
<p>Yes — <code>commitText('ا')</code> (Arabic) works exactly like <code>commitText('a')</code>. RTL layout direction
(row/key alignment) is handled with standard React Native <code>flexDirection</code>/<code>I18nManager</code>, the same
way any RTL screen is built.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it-yourself">Try it yourself<a href="https://keyboardbridge.github.io/blog/any-language-any-script#try-it-yourself" class="hash-link" aria-label="Direct link to Try it yourself" title="Direct link to Try it yourself" translate="no">​</a></h2>
<p>This is a real, working library, not a proof-of-concept — install it and build your own keyboard:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">yarn add react-native-keyboard-bridge</span><br></div></code></pre></div></div>
<ul>
<li class="">📖 <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/" target="_blank" rel="noopener noreferrer" class="">Full documentation &amp; tutorial</a></li>
<li class="">⭐ <a href="https://github.com/DeveloperRejaul/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Source on GitHub</a></li>
<li class="">📦 <a href="https://www.npmjs.com/package/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Package on npm</a></li>
</ul>]]></content:encoded>
            <category>i18n</category>
            <category>react-native</category>
            <category>keyboard</category>
        </item>
        <item>
            <title><![CDATA[How to Build a Custom Keyboard in React Native (Step-by-Step Tutorial)]]></title>
            <link>https://keyboardbridge.github.io/blog/building-your-first-keyboard</link>
            <guid>https://keyboardbridge.github.io/blog/building-your-first-keyboard</guid>
            <pubDate>Sat, 20 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A complete step-by-step tutorial for building a real, working QWERTY keyboard in React Native — shift, backspace, space, enter, and registering it as a system keyboard on Android and iOS.]]></description>
            <content:encoded><![CDATA[<p>This is the walkthrough version of the <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/tutorial/basic-keyboard" target="_blank" rel="noopener noreferrer" class="">Tutorial</a> — a from-scratch
build of a real, usable QWERTY keyboard, explained step by step.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="start-with-the-keys">Start with the keys<a href="https://keyboardbridge.github.io/blog/building-your-first-keyboard#start-with-the-keys" class="hash-link" aria-label="Direct link to Start with the keys" title="Direct link to Start with the keys" translate="no">​</a></h2>
<p>A keyboard component is just state plus a grid of buttons. No special base class, no required
props shape:</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> useState </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">View</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">Text</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">TouchableOpacity</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">StyleSheet</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react-native'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> commitText</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> deleteSurroundingText </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react-native-keyboard-bridge'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">ROWS</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'q'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'w'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'e'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'r'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'t'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'y'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'u'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'i'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'o'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'p'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'a'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'s'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'d'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'f'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'g'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'h'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'j'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'k'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'l'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'z'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'x'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'c'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'v'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'b'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'n'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'m'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">KeyboardApp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">shift</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setShift</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">press</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">letter</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token function" style="color:#d73a49">commitText</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">shift </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> letter</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toUpperCase</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> letter</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">shift</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">setShift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">View</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">style</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">styles</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">container</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token constant" style="color:#36acaa">ROWS</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">row</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">View</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">key</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">i</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">style</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">styles</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">row</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">          </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">row</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">letter</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">key</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">letter</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">style</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">styles</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">key</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onPress</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript function" style="color:#d73a49">press</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript" style="color:#00009f">letter</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">              </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">style</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">styles</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">label</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">shift </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> letter</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toUpperCase</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> letter</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">            </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">        </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">View</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">View</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span><br></div></code></pre></div></div>
<p><code>commitText</code> is the one function doing the real work — it inserts text at the cursor through
<code>InputConnection</code> on Android and <code>textDocumentProxy</code> on iOS. Everything else here is plain React
Native UI.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="add-shift-backspace-space-and-enter">Add shift, backspace, space, and enter<a href="https://keyboardbridge.github.io/blog/building-your-first-keyboard#add-shift-backspace-space-and-enter" class="hash-link" aria-label="Direct link to Add shift, backspace, space, and enter" title="Direct link to Add shift, backspace, space, and enter" translate="no">​</a></h2>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onPress</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript function" style="color:#d73a49">setShift</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript" style="color:#00009f">s</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript operator" style="color:#393A34">!</span><span class="token tag script language-javascript" style="color:#00009f">s</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">  </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">⇧</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onPress</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript function" style="color:#d73a49">deleteSurroundingText</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript number" style="color:#36acaa">1</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript number" style="color:#36acaa">0</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">  </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">⌫</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onPress</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript function" style="color:#d73a49">commitText</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript string" style="color:#e3116c">' '</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">  </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">space</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onPress</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript function" style="color:#d73a49">commitText</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript string" style="color:#e3116c">'\n'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">  </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">⏎</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag punctuation" style="color:#393A34">&gt;</span></span><br></div></code></pre></div></div>
<p><code>deleteSurroundingText(before, after)</code> removes characters relative to the cursor — <code>(1, 0)</code> is a
standard single-character backspace. There's no special "enter" API to call; committing a newline
character is exactly what a hardware Return key does from the text field's point of view.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="register-it">Register it<a href="https://keyboardbridge.github.io/blog/building-your-first-keyboard#register-it" class="hash-link" aria-label="Direct link to Register it" title="Direct link to Register it" translate="no">​</a></h2>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">index.js</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">AppRegistry</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react-native'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">KeyboardApp</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'./src/keyboard/KeyboardApp'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token maybe-class-name">AppRegistry</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">registerComponent</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'KeyboardApp'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token maybe-class-name">KeyboardApp</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span></span><br></div></code></pre></div></div>
<p>The name <code>KeyboardApp</code> is fixed — both native modules request a surface with exactly this
component name. Run <code>npx react-native-keyboard-bridge setup-ios</code> once for the iOS App Extension
target, and Android needs no extra wiring at all.</p>
<p>That's a fully working keyboard in under 60 lines. From here, the <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/tutorial/basic-keyboard" target="_blank" rel="noopener noreferrer" class="">full tutorial</a>
continues into multi-language layouts, swipe typing, word prediction, and the polish details
(haptics, click sounds, auto-capitalization) that make a keyboard feel native.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="frequently-asked-questions">Frequently asked questions<a href="https://keyboardbridge.github.io/blog/building-your-first-keyboard#frequently-asked-questions" class="hash-link" aria-label="Direct link to Frequently asked questions" title="Direct link to Frequently asked questions" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-do-i-make-a-custom-keyboard-in-react-native">How do I make a custom keyboard in React Native?<a href="https://keyboardbridge.github.io/blog/building-your-first-keyboard#how-do-i-make-a-custom-keyboard-in-react-native" class="hash-link" aria-label="Direct link to How do I make a custom keyboard in React Native?" title="Direct link to How do I make a custom keyboard in React Native?" translate="no">​</a></h3>
<p>Write a plain component using <code>View</code>/<code>Text</code>/<code>TouchableOpacity</code>, call <code>commitText</code>/
<code>deleteSurroundingText</code> from <code>react-native-keyboard-bridge</code> on key presses, and register it under
the fixed name <code>KeyboardApp</code> in your <code>index.js</code>. No schema or special base class required.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="do-i-need-a-different-component-for-android-and-ios">Do I need a different component for Android and iOS?<a href="https://keyboardbridge.github.io/blog/building-your-first-keyboard#do-i-need-a-different-component-for-android-and-ios" class="hash-link" aria-label="Direct link to Do I need a different component for Android and iOS?" title="Direct link to Do I need a different component for Android and iOS?" translate="no">​</a></h3>
<p>No — the exact same <code>KeyboardApp.tsx</code> file runs unmodified on both platforms.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-does-the-backspace-key-work">How does the backspace key work?<a href="https://keyboardbridge.github.io/blog/building-your-first-keyboard#how-does-the-backspace-key-work" class="hash-link" aria-label="Direct link to How does the backspace key work?" title="Direct link to How does the backspace key work?" translate="no">​</a></h3>
<p><code>deleteSurroundingText(before, after)</code> removes characters relative to the cursor —
<code>deleteSurroundingText(1, 0)</code> deletes exactly one character before the cursor, the same as a
standard backspace.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it-yourself">Try it yourself<a href="https://keyboardbridge.github.io/blog/building-your-first-keyboard#try-it-yourself" class="hash-link" aria-label="Direct link to Try it yourself" title="Direct link to Try it yourself" translate="no">​</a></h2>
<p>This is a real, working library, not a proof-of-concept — install it and build your own keyboard:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">yarn add react-native-keyboard-bridge</span><br></div></code></pre></div></div>
<ul>
<li class="">📖 <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/" target="_blank" rel="noopener noreferrer" class="">Full documentation &amp; tutorial</a></li>
<li class="">⭐ <a href="https://github.com/DeveloperRejaul/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Source on GitHub</a></li>
<li class="">📦 <a href="https://www.npmjs.com/package/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">Package on npm</a></li>
</ul>]]></content:encoded>
            <category>tutorial</category>
            <category>react-native</category>
            <category>keyboard</category>
        </item>
        <item>
            <title><![CDATA[Can You Build a Custom Keyboard App in React Native? (Yes — Here's How)]]></title>
            <link>https://keyboardbridge.github.io/blog/announcing-react-native-keyboard-bridge</link>
            <guid>https://keyboardbridge.github.io/blog/announcing-react-native-keyboard-bridge</guid>
            <pubDate>Mon, 01 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Build a real Android IME and iOS Custom Keyboard Extension using only React Native components — no native Kotlin/Swift UI required. Here's how react-native-keyboard-bridge makes it possible.]]></description>
            <content:encoded><![CDATA[<p>Can you actually build a production system keyboard — an Android IME, an iOS Custom Keyboard
Extension — entirely in React Native? Not a demo, not a toy, but something you'd ship to real
users on both platforms from one codebase?</p>
<p><strong>Yes. This is the proof, and the library that makes it repeatable.</strong></p>
<p>Every mobile app that wants a custom system keyboard has run into the same wall: Android IMEs and
iOS Custom Keyboard Extensions are native surfaces. Building one has always meant writing (and
maintaining) two separate native UIs in Kotlin and Swift — even if your app is otherwise 100%
React Native. Most teams either give up on the idea or pay for a fully native rewrite of a single
screen.</p>
<p><strong>react-native-keyboard-bridge</strong> removes that wall. You write one component — plain <code>View</code>,
<code>Text</code>, <code>TouchableOpacity</code>, <code>useState</code> — and it runs live on both platforms, as a real, live React
Native surface hosted inside the IME process on Android and the Custom Keyboard Extension process
on iOS. Not a schema. Not a subset. Real React Native, running where conventional wisdom said it
couldn't.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-runs-live-actually-means">What "runs live" actually means<a href="https://keyboardbridge.github.io/blog/announcing-react-native-keyboard-bridge#what-runs-live-actually-means" class="hash-link" aria-label="Direct link to What &quot;runs live&quot; actually means" title="Direct link to What &quot;runs live&quot; actually means" translate="no">​</a></h2>
<p>This isn't a schema you configure, and it isn't a compiled subset of JSX rendered by a
hand-written interpreter. It's Hermes + JSI + Fabric — the exact same New Architecture stack any
other React Native screen in your app uses — hosted inside a process that most people assumed
couldn't afford it.</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> useState </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">View</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">Text</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">TouchableOpacity</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">StyleSheet</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react-native'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> commitText</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> deleteSurroundingText </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react-native-keyboard-bridge'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">KeyboardApp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">shifted</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setShifted</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">View</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">style</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">styles</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">row</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'q'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'w'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'e'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'r'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'t'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'y'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">key</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">key</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onPress</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript function" style="color:#d73a49">commitText</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript" style="color:#00009f">shifted </span><span class="token tag script language-javascript operator" style="color:#393A34">?</span><span class="token tag script language-javascript" style="color:#00009f"> key</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript method function property-access" style="color:#d73a49">toUpperCase</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> key</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">          </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">style</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">styles</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">key</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">shifted </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toUpperCase</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">        </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onPress</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript function" style="color:#d73a49">deleteSurroundingText</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript number" style="color:#36acaa">1</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript number" style="color:#36acaa">0</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">style</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">styles</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">key</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">⌫</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Text</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">TouchableOpacity</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">View</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> styles </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">StyleSheet</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  row</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> flexDirection</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'row'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> justifyContent</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'space-around'</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  key</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> fontSize</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">18</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> padding</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">8</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></div><div class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span></span><br></div></code></pre></div></div>
<p>That's the entire keyboard. No <code>KeyLayout</code> schema to learn, no proprietary DSL, no
platform-specific branch in your component. <code>commitText</code> takes a plain Unicode string, so this
works identically whether you're typing English, Bangla, Arabic, or any other script.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="one-install">One install<a href="https://keyboardbridge.github.io/blog/announcing-react-native-keyboard-bridge#one-install" class="hash-link" aria-label="Direct link to One install" title="Direct link to One install" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">yarn add react-native-keyboard-bridge</span><br></div></code></pre></div></div>
<p>The JS bridge, the Android native module (autolinked), the iOS native module, gesture/
swipe-typing helpers, word prediction, and the iOS setup CLI all ship in this single package. See
the <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/installation" target="_blank" rel="noopener noreferrer" class="">Installation guide</a> to get a keyboard running in your app today, or read
<a href="https://developerrejaul.github.io/react-native-keyboard-bridge/blog/building-your-first-keyboard" target="_blank" rel="noopener noreferrer" class="">Building Your First Keyboard</a> for a full walkthrough.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="frequently-asked-questions">Frequently asked questions<a href="https://keyboardbridge.github.io/blog/announcing-react-native-keyboard-bridge#frequently-asked-questions" class="hash-link" aria-label="Direct link to Frequently asked questions" title="Direct link to Frequently asked questions" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="can-you-build-a-custom-keyboard-app-with-react-native">Can you build a custom keyboard app with React Native?<a href="https://keyboardbridge.github.io/blog/announcing-react-native-keyboard-bridge#can-you-build-a-custom-keyboard-app-with-react-native" class="hash-link" aria-label="Direct link to Can you build a custom keyboard app with React Native?" title="Direct link to Can you build a custom keyboard app with React Native?" translate="no">​</a></h3>
<p>Yes. <code>react-native-keyboard-bridge</code> hosts a real, live React Native runtime — Hermes, JSI, and
Fabric — directly inside the Android IME process and the iOS Custom Keyboard Extension process.
Your keyboard component runs unmodified, the same way any other React Native screen does.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="is-it-a-real-android-ime-and-a-real-ios-custom-keyboard-extension-or-just-a-demo">Is it a real Android IME and a real iOS Custom Keyboard Extension, or just a demo?<a href="https://keyboardbridge.github.io/blog/announcing-react-native-keyboard-bridge#is-it-a-real-android-ime-and-a-real-ios-custom-keyboard-extension-or-just-a-demo" class="hash-link" aria-label="Direct link to Is it a real Android IME and a real iOS Custom Keyboard Extension, or just a demo?" title="Direct link to Is it a real Android IME and a real iOS Custom Keyboard Extension, or just a demo?" translate="no">​</a></h3>
<p>Both are real, installable system keyboards. On Android, <code>CustomKeyboardService</code> extends
<code>InputMethodService</code> directly. On iOS, <code>KeyboardViewController</code> extends <code>UIInputViewController</code>
inside a genuine Xcode App Extension target. Once installed and enabled, either one appears in the
OS keyboard list exactly like any native keyboard app.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="do-i-need-to-write-any-native-kotlin-or-swift-code">Do I need to write any native Kotlin or Swift code?<a href="https://keyboardbridge.github.io/blog/announcing-react-native-keyboard-bridge#do-i-need-to-write-any-native-kotlin-or-swift-code" class="hash-link" aria-label="Direct link to Do I need to write any native Kotlin or Swift code?" title="Direct link to Do I need to write any native Kotlin or Swift code?" translate="no">​</a></h3>
<p>No. The native side (Kotlin on Android, Swift on iOS) is entirely provided by the library — it
only wires up the runtime and a text-editing bridge. Your own code is 100% React Native/TypeScript.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="does-it-support-languages-other-than-english">Does it support languages other than English?<a href="https://keyboardbridge.github.io/blog/announcing-react-native-keyboard-bridge#does-it-support-languages-other-than-english" class="hash-link" aria-label="Direct link to Does it support languages other than English?" title="Direct link to Does it support languages other than English?" translate="no">​</a></h3>
<p>Yes — <code>commitText</code> takes a plain Unicode string with no script whitelist, so Bangla, Arabic,
Devanagari, CJK, Cyrillic, and right-to-left layouts all work identically to English. See
<a href="https://developerrejaul.github.io/react-native-keyboard-bridge/blog/any-language-any-script" target="_blank" rel="noopener noreferrer" class="">How to Support Multiple Languages in a React Native Keyboard</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-react-native-version-does-it-require">What React Native version does it require?<a href="https://keyboardbridge.github.io/blog/announcing-react-native-keyboard-bridge#what-react-native-version-does-it-require" class="hash-link" aria-label="Direct link to What React Native version does it require?" title="Direct link to What React Native version does it require?" translate="no">​</a></h3>
<p>React Native 0.74 or later (New Architecture / Fabric), since the library depends on <code>ReactHost</code>
on Android and <code>RCTReactNativeFactory</code> on iOS — both New Architecture APIs.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it-yourself">Try it yourself<a href="https://keyboardbridge.github.io/blog/announcing-react-native-keyboard-bridge#try-it-yourself" class="hash-link" aria-label="Direct link to Try it yourself" title="Direct link to Try it yourself" translate="no">​</a></h2>
<ul>
<li class="">📦 Install: <code>yarn add react-native-keyboard-bridge</code></li>
<li class="">📖 Full docs &amp; step-by-step tutorial: <a href="https://developerrejaul.github.io/react-native-keyboard-bridge/docs/" target="_blank" rel="noopener noreferrer" class="">developerrejaul.github.io/react-native-keyboard-bridge</a></li>
<li class="">⭐ Source &amp; issues: <a href="https://github.com/DeveloperRejaul/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">github.com/DeveloperRejaul/react-native-keyboard-bridge</a></li>
<li class="">📦 Package: <a href="https://www.npmjs.com/package/react-native-keyboard-bridge" target="_blank" rel="noopener noreferrer" class="">npmjs.com/package/react-native-keyboard-bridge</a></li>
</ul>
<p>If you've ever been told "you can't build a real keyboard in React Native," this library — and
the working example app in the repo — is the counter-argument.</p>]]></content:encoded>
            <category>announcement</category>
            <category>react-native</category>
            <category>keyboard</category>
            <category>android</category>
            <category>ios</category>
        </item>
    </channel>
</rss>