RORK LABJP
RORK-MAX — Rork Max builds native Swift apps ($200/mo) for iPhone, iPad, Watch, TV, Vision Pro, and iMessage, with AR/LiDAR and Live ActivitiesCLOUD-MAC — Rork Max compiles natively on a cloud Mac fleet, so you publish to the App Store in two clicks with no Xcode and no MacEXPO — The original Rork generates production iOS/Android apps from a description via Expo (React Native); free to start, paid from $25/moWWDC — WWDC 2026 unveils iOS 27 for iPhone 11 and later, with photos 70% faster and AirDrop 80% faster; it ships this fall with iPhone 18 ProANDROID17 — Android 17 is expected stable in June; mandatory large-screen resizability makes foldable and tablet support a baseline for appsSIRI-INTENTS — iOS 27's Siri is rebuilt on Gemini, making native apps with solid App Intents integration worth revisiting in your designRORK-MAX — Rork Max builds native Swift apps ($200/mo) for iPhone, iPad, Watch, TV, Vision Pro, and iMessage, with AR/LiDAR and Live ActivitiesCLOUD-MAC — Rork Max compiles natively on a cloud Mac fleet, so you publish to the App Store in two clicks with no Xcode and no MacEXPO — The original Rork generates production iOS/Android apps from a description via Expo (React Native); free to start, paid from $25/moWWDC — WWDC 2026 unveils iOS 27 for iPhone 11 and later, with photos 70% faster and AirDrop 80% faster; it ships this fall with iPhone 18 ProANDROID17 — Android 17 is expected stable in June; mandatory large-screen resizability makes foldable and tablet support a baseline for appsSIRI-INTENTS — iOS 27's Siri is rebuilt on Gemini, making native apps with solid App Intents integration worth revisiting in your design
Articles/Dev Tools
Dev Tools/2026-04-15Intermediate

Fix Keyboard Hiding Input Fields in Rork Apps: A Complete Troubleshooting Guide

Solve the common issue of the on-screen keyboard overlapping text input fields in Rork apps. Learn KeyboardAvoidingView, ScrollView combinations, the useKeyboard hook, and SwiftUI keyboard avoidance with working code examples.

Rork481keyboardKeyboardAvoidingViewReact Native205Expo77troubleshooting72forms

Build a form screen, tap a text field, and suddenly the keyboard slides up — covering the very input the user is trying to fill out. If you've been building apps with Rork, you've almost certainly hit this. What makes it especially frustrating is that iOS and Android behave differently, so a fix that works on one platform quietly breaks the other.

This guide walks through the root cause, then gives you working code for each scenario you're likely to encounter.

Why This Happens

React Native (the framework underlying Rork) doesn't automatically scroll content upward when the software keyboard appears. Unlike a mobile browser, the framework won't naturally resize or shift the layout to keep the focused input visible — you have to wire that up yourself.

The behavior also differs between platforms. iOS expects the padding behavior prop, while Android relies on the native windowSoftInputMode setting, which you can control in app.json for Expo managed projects.

First Check: softwareKeyboardLayoutMode in app.json

{
  "expo": {
    "android": {
      "softwareKeyboardLayoutMode": "pan"
    }
  }
}

Setting this to "pan" makes the entire screen slide up on Android when the keyboard appears. "resize" shrinks the content area instead. For most form screens, "pan" feels more natural.

One important caveat: this setting is Android-only. iOS ignores it entirely, so you'll need a separate solution for Apple devices.

The Standard Fix: KeyboardAvoidingView

import {
  KeyboardAvoidingView,
  Platform,
  ScrollView,
  TextInput,
  StyleSheet,
} from 'react-native';
 
export default function ContactForm() {
  return (
    <KeyboardAvoidingView
      style={styles.container}
      behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
      keyboardVerticalOffset={Platform.OS === 'ios' ? 90 : 0}
    >
      <ScrollView
        contentContainerStyle={styles.scrollContent}
        keyboardShouldPersistTaps="handled"
      >
        <TextInput
          style={styles.input}
          placeholder="Name"
          returnKeyType="next"
        />
        <TextInput
          style={styles.input}
          placeholder="Email address"
          keyboardType="email-address"
          returnKeyType="next"
        />
        <TextInput
          style={styles.input}
          placeholder="Message"
          multiline
          numberOfLines={6}
          textAlignVertical="top"
        />
      </ScrollView>
    </KeyboardAvoidingView>
  );
}
 
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  scrollContent: {
    padding: 16,
    paddingBottom: 40,
  },
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 8,
    padding: 12,
    marginBottom: 16,
    fontSize: 16,
  },
});

Two things are critical here.

First, always branch the behavior prop with Platform.OS. iOS needs 'padding'; Android works better with 'height'. Leaving it undefined means iOS gets nothing.

Second, tune keyboardVerticalOffset to match your navigation bar height. With Expo Router's default stack header, 90 is usually close. If you're using a custom header, measure its actual height and adjust accordingly.

A Common Mistake: Forgetting the ScrollView

Adding KeyboardAvoidingView alone isn't enough if your form is tall. Without ScrollView inside it, inputs that scroll off the top of the screen are unreachable. Always pair them.

Also set keyboardShouldPersistTaps="handled" on the ScrollView. Without it, tapping outside a text field might not dismiss the keyboard, and taps on buttons inside the scroll area can get swallowed before they register.

For Chat-Style Layouts: useKeyboard Hook

When KeyboardAvoidingView doesn't behave (this happens frequently with bottom sheets, modals, and animated transitions), reading keyboard height directly gives you full control.

import { useEffect, useState } from 'react';
import { Keyboard, KeyboardEvent, Platform } from 'react-native';
 
export function useKeyboardHeight() {
  const [keyboardHeight, setKeyboardHeight] = useState(0);
 
  useEffect(() => {
    const showEvent =
      Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
    const hideEvent =
      Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';
 
    const showSub = Keyboard.addListener(
      showEvent,
      (e: KeyboardEvent) => {
        setKeyboardHeight(e.endCoordinates.height);
      }
    );
    const hideSub = Keyboard.addListener(hideEvent, () => {
      setKeyboardHeight(0);
    });
 
    return () => {
      showSub.remove();
      hideSub.remove();
    };
  }, []);
 
  return keyboardHeight;
}
export default function ChatScreen() {
  const keyboardHeight = useKeyboardHeight();
 
  return (
    <View style={{ flex: 1 }}>
      <FlatList data={messages} /* ... */ />
      <View
        style={{
          paddingBottom: keyboardHeight > 0 ? keyboardHeight : 16,
          borderTopWidth: 1,
          borderTopColor: '#eee',
          padding: 8,
        }}
      >
        <TextInput placeholder="Type a message..." />
      </View>
    </View>
  );
}

This pattern works well for chat UIs where the input bar is pinned to the bottom. The re-render on keyboard height change is lightweight enough that it won't cause performance issues in a typical chat screen.

Rork Max (SwiftUI): Different Rules Apply

If you're generating a native SwiftUI app with Rork Max, the React Native approach doesn't apply. In SwiftUI, use .ignoresSafeArea(.keyboard) with a ScrollView.

struct ContactFormView: View {
    @State private var name = ""
    @State private var email = ""
    @State private var message = ""
 
    var body: some View {
        ScrollView {
            VStack(spacing: 16) {
                TextField("Name", text: $name)
                    .textFieldStyle(.roundedBorder)
                TextField("Email", text: $email)
                    .textFieldStyle(.roundedBorder)
                    .keyboardType(.emailAddress)
                TextEditor(text: $message)
                    .frame(height: 120)
                    .border(Color.gray.opacity(0.3))
            }
            .padding()
        }
        // Required when TextEditor is near the bottom of the screen
        .ignoresSafeArea(.keyboard, edges: .bottom)
    }
}

SwiftUI has built-in keyboard avoidance since iOS 15, but TextEditor specifically can still be obscured if the .ignoresSafeArea(.keyboard) modifier is missing. It's a small detail that's easy to overlook.

Tab Bar Screens Need Extra Offset

When your form is inside a tab-based navigation (Expo Router's Tabs, for example), add the tab bar height to keyboardVerticalOffset.

import { useSafeAreaInsets } from 'react-native-safe-area-context';
 
function FormInsideTabs() {
  const insets = useSafeAreaInsets();
  const TAB_BAR_HEIGHT = 49; // Expo Router default
 
  return (
    <KeyboardAvoidingView
      style={{ flex: 1 }}
      behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
      keyboardVerticalOffset={TAB_BAR_HEIGHT + insets.bottom}
    >
      {/* form content */}
    </KeyboardAvoidingView>
  );
}

The keyboardVerticalOffset tells the component where to anchor its calculations. Leaving out the tab bar height causes the layout to shift by the wrong amount — sometimes barely noticeable, sometimes wildly off.

Choosing the Right Approach

  • Simple forms (login, contact): KeyboardAvoidingView + ScrollView covers most cases.
  • Chat UI or fixed bottom input: Use the useKeyboardHeight hook for reliable control.
  • Rork Max (SwiftUI): Add .ignoresSafeArea(.keyboard) and let SwiftUI handle the rest.
  • Screens inside a tab navigator: Include tab bar height in keyboardVerticalOffset.

For related layout issues, see the Rork App Layout and Responsive Design Troubleshooting Guide. If you want to add input validation alongside these fixes, Form Validation with react-hook-form and Zod walks through that step by step.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Dev Tools2026-04-20
Why useEffect Loops Infinitely in Rork-Generated Code — and How to Fix It
Rork-generated React Native code can trigger useEffect infinite loops through subtle dependency array mistakes. This guide covers 5 common causes — stale deps, object references, unstable callbacks — with Before/After code fixes.
Dev Tools2026-04-12
Rork App Running Slow, Lagging, or Freezing? A Complete Performance Troubleshooting Guide
Diagnose and fix performance issues in your Rork-built app — from laggy scrolling and slow transitions to freezes and memory leaks. Includes code examples for React Native optimization.
Dev Tools2026-05-28
Tracking Down BGTaskScheduler.submit Error Code=1 (Unavailable) in Rork iOS Apps
A field-tested checklist for diagnosing BGTaskScheduler.submit failing with Error Code=1 (Unavailable) in iOS apps built with Rork, walking through the six causes that account for nearly every case.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →