RORK LABJP
CLOUD — Rork Max compiles Swift on a cloud Mac fleet and streams the simulator to your browser, so no Xcode or Mac is requiredSIM — The streamed simulator runs at 60fps and accepts real touch input in the browser, letting you feel the app without a deviceNATIVE — You get native capabilities like AR and LiDAR scanning, Metal-backed 3D rendering, and on-device inference with Core MLWIDGET — Home Screen widgets, Dynamic Island, Live Activities, Siri Intents, HealthKit, NFC, and App Clips are all in reachARR — Rork Max reached $1.5M ARR within three days of its February 2026 launch, a fair signal of demand for native generationIOS27 — The iOS 27 public beta arrived in mid-July, so now is the time to check generated apps ahead of the autumn releaseCLOUD — Rork Max compiles Swift on a cloud Mac fleet and streams the simulator to your browser, so no Xcode or Mac is requiredSIM — The streamed simulator runs at 60fps and accepts real touch input in the browser, letting you feel the app without a deviceNATIVE — You get native capabilities like AR and LiDAR scanning, Metal-backed 3D rendering, and on-device inference with Core MLWIDGET — Home Screen widgets, Dynamic Island, Live Activities, Siri Intents, HealthKit, NFC, and App Clips are all in reachARR — Rork Max reached $1.5M ARR within three days of its February 2026 launch, a fair signal of demand for native generationIOS27 — The iOS 27 public beta arrived in mid-July, so now is the time to check generated apps ahead of the autumn release
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.

Rork519keyboardKeyboardAvoidingViewReact Native211Expo149troubleshooting65forms2

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-07-15
The Comma That Fell to the Start of a Line: Rork, Quote Cards, and Japanese Line Breaking
React Native's Text component does not guarantee Japanese line-breaking rules. Here are the violation rates I measured, a WORD JOINER implementation that survives copy and VoiceOver, an onTextLayout audit harness, and how Rork Max (SwiftUI) differs.
📚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 →