Skip to content
Back to blog
Whispcal

Keyboard hell and other React Native nightmares

react-nativekeyboardiosdebuggingmobile-dev

If you've never built a mobile app with heavy text input, let me paint you a picture: the keyboard is not your friend. It's an unpredictable, platform-specific, layout-destroying force of nature that will make you question every life choice that led you to mobile development.

WhispCal is a text-heavy app. The core interaction is typing (or speaking) what you ate. That means the keyboard is on screen constantly. And on React Native, that's where the pain lives.

The first wave

The early signs were subtle. On December 23rd, I pushed a commit called "refactoring using new keyboard library along with a DuoModal." That's the diplomatic version. The real story: the default React Native keyboard handling was pushing my modals off-screen, overlapping input fields, and behaving differently on iOS and Android.

I tried KeyboardAvoidingView. I tried KeyboardAwareScrollView. I tried manually listening to keyboard events and adjusting layouts. Each solution fixed one thing and broke another.

Pauline's iPhone

By New Year's Eve, I had two keyboard-related commits in a single day: "dismiss keyboard to avoid weird Pauline ios issues" and "dismiss top summary nutritional strip when we open the keyboard."

Pauline is my partner, and her iPhone became my most reliable QA device — mostly because she actually used the app for real meals and found bugs I never would have. The "weird Pauline ios issues" were cases where the keyboard would push content behind the navigation bar, or the nutritional summary strip would overlap the input field, making it impossible to see what you were typing.

The fix was pragmatic and ugly: detect when the keyboard opens, hide non-essential UI elements, and force-dismiss the keyboard when navigating between screens. It works. It's not the kind of solution you'd put in a conference talk.

The bottom sheet saga

One of the most painful refactors was removing gorhom/bottom-sheet. This library is popular in the React Native ecosystem for creating iOS-style bottom sheets, and I used it extensively for food search, recipe details, and item editing.

The problem: it fought with the keyboard. When a bottom sheet contained a text input and the keyboard appeared, the sheet would either not resize properly, jump to the wrong position, or — my personal favorite — trap the keyboard in a state where it couldn't be dismissed.

On December 29th I ripped it out entirely: "remove gorhom and refactor busy chef loader" followed by "remove gorhom bottom sheet." Two commits, one afternoon, and dozens of components that needed new container logic. I replaced it with simpler modal-based patterns that played nicer with keyboard events.

The log meal keyboard crisis

The worst keyboard bug hit in late February: "fix keyboard on log-meal hiding content." The log meal screen is the most important screen in the app — it's where you type what you ate and see the AI's interpretation. If the keyboard hides the content, the app is essentially broken.

The root cause was a cascade of layout issues: the sticky footer (log button), the nutritional impact strip, the food item list, and the text input all competing for vertical space when the keyboard appeared. On smaller iPhones, there simply wasn't enough room.

I ended up building a custom layout system that dynamically adjusted based on keyboard state, device size, and which elements were currently visible. It's the least glamorous code in the entire project, and arguably the most important.

Lessons from the keyboard trenches

  • Test on real devices early. The iOS Simulator keyboard behaves differently from a physical device. I learned this the hard way.
  • Don't fight the platform. When the keyboard wants space, give it space. Trying to be clever with custom animations or layout hacks always backfires.
  • Your most important screen needs the most keyboard testing. I should have stress-tested the log meal input from day one instead of treating keyboard handling as an afterthought.
  • Sometimes removing a dependency is the fix. The gorhom bottom sheet is a good library. It just wasn't compatible with my specific use case. Admitting that and moving on saved me weeks of workaround code.

The keyboard still isn't perfect. I doubt it ever will be. But it's gone from "actively hostile" to "occasionally annoying," and in React Native development, that counts as victory.