npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-fieldflow

v1.3.0

Published

High-performance React Native keyboard avoidance and zero-config focus chaining. Now featuring Chat Mode for WhatsApp-style chat inputs and 120fps synchronized accessory views on both iOS and Android.

Downloads

532

Readme

npm React Native Expo License Stars

If this saves you time, consider starring the repo — it helps other developers find it.


📱 Demo


📦 Installation

npm install react-native-fieldflow

Requirements: React Native ≥ 0.68 · Expo & bare RN supported · Zero native modules · No pod install


⚡ Quick Start

Drop FieldForm and FieldInput into any screen. Focus chaining, keyboard avoidance, and return key types are all handled automatically.

import { FieldForm, FieldInput } from "react-native-fieldflow";

export default function SignUpScreen() {
  return (
    <FieldForm onSubmit={handleSubmit}>
      <FieldInput placeholder="Full name" textContentType="name" />
      <FieldInput
        placeholder="Email"
        textContentType="emailAddress"
        keyboardType="email-address"
        autoCapitalize="none"
      />
      <FieldInput
        placeholder="Phone"
        textContentType="telephoneNumber"
        keyboardType="phone-pad"
      />
      <FieldInput
        placeholder="Password"
        textContentType="newPassword"
        secureTextEntry
      />
      <FieldInput
        placeholder="Confirm password"
        textContentType="newPassword"
        secureTextEntry
      />
    </FieldForm>
  );
}

What you get for free:

| | | | ------------------------- | ------------------------------------------------------------------- | | 🔗 Focus chaining | Fields 1–4 get returnKeyType="next", the last field gets "done" | | ⌨️ Keyboard avoidance | Smooth animated layout shift — no jumps, no native modules | | 🛠️ Accessory views | Cross-platform floating toolbars, perfectly synced with animations | | 📜 Auto scroll | Focused field is always scrolled into view above the keyboard | | 📱 Cross-platform | Identical behavior on iOS and Android, no Platform.OS switches |


🔄 Before & After

❌ Without FieldFlow — 5 refs · 5 wired handlers · platform switches · 40+ lines

const nameRef = useRef<TextInput>(null);
const emailRef = useRef<TextInput>(null);
const phoneRef = useRef<TextInput>(null);
const passRef = useRef<TextInput>(null);
const confirmRef = useRef<TextInput>(null);

<KeyboardAvoidingView
  behavior={Platform.OS === "ios" ? "padding" : "height"}
  keyboardVerticalOffset={Platform.OS === "ios" ? 64 : 0}
  style={{ flex: 1 }}
>
  <ScrollView keyboardShouldPersistTaps="handled">
    <TextInput
      ref={nameRef}
      returnKeyType="next"
      blurOnSubmit={false}
      onSubmitEditing={() => emailRef.current?.focus()}
    />
    <TextInput
      ref={emailRef}
      returnKeyType="next"
      blurOnSubmit={false}
      onSubmitEditing={() => phoneRef.current?.focus()}
    />
    <TextInput
      ref={phoneRef}
      returnKeyType="next"
      blurOnSubmit={false}
      onSubmitEditing={() => passRef.current?.focus()}
    />
    <TextInput
      ref={passRef}
      returnKeyType="next"
      blurOnSubmit={false}
      onSubmitEditing={() => confirmRef.current?.focus()}
    />
    <TextInput
      ref={confirmRef}
      returnKeyType="done"
      onSubmitEditing={handleSubmit}
    />
  </ScrollView>
</KeyboardAvoidingView>;

✅ With FieldFlow — 0 refs · 0 handlers · 0 platform switches · 8 lines

import { FieldForm, FieldInput } from "react-native-fieldflow";

<FieldForm onSubmit={handleSubmit}>
  <FieldInput placeholder="Full name" />
  <FieldInput
    placeholder="Email"
    keyboardType="email-address"
    autoCapitalize="none"
  />
  <FieldInput placeholder="Phone" keyboardType="phone-pad" />
  <FieldInput placeholder="Password" secureTextEntry />
  <FieldInput placeholder="Confirm" secureTextEntry />
</FieldForm>;

🏗 How It Works

| Layer | What happens | | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | Keyboard tracking | Uses native keyboard listeners to track frame changes — zero native modules required | | Spacer | An Animated.View at the bottom of the scroll content grows to match the keyboard frame, pushing content up in sync | | Focus chain | Every FieldInput registers itself into an ordered list; tapping Next calls focus() on the next ref and scrolls it into view above the keyboard | | Submit | The last field's Done button calls onSubmit and dismisses the keyboard |

Everything runs in JS — no native modules required. Works on Expo, bare RN, and New Architecture (Fabric).


📖 API Reference

<FieldForm>

The wrapper component that manages keyboard avoidance, scroll behavior, and the focus chain.

| Prop | Type | Default | Description | | --------------------------- | -------------------------------- | ---------- | ------------------------------------------------------------------------------------------------- | | onSubmit | () => void | — | Called when the last field's Done is tapped | | extraScrollPadding | number | 140 | Gap (px) between the active field and the keyboard top edge | | scrollable | boolean | true | Wrap children in a managed ScrollView | | avoidKeyboard | boolean | true | Enable the animated keyboard spacer | | keyboardAccessoryView | ReactNode | — | Toolbar that floats above the keyboard on both platforms | | keyboardAccessoryViewMode | 'always' \| 'whenKeyboardOpen' | 'always' | always — always visible, lifts with keyboard · whenKeyboardOpen — hidden until keyboard opens | | autoScroll | boolean | true | Scroll to focused field automatically | | chainEnabled | boolean | true | Auto-focus next field on Next / Done | | autoReturnKeyType | boolean | true | Auto-set returnKeyType to next / done | | dismissKeyboardOnTap | boolean | false | Tap outside any input to dismiss the keyboard | | submitOnLastFieldDone | boolean | false | Call onSubmit when Done is pressed on the final field | | chatMode | boolean | false | High-performance mode for chat screens — bypasses padding and uses native scrollToEnd() | | scrollViewProps | ScrollViewProps | — | Forwarded directly to the internal ScrollView | | keyboardVerticalOffset | number \| (platform) => number | 0 / 25 | Static offset or per-platform resolver function | | onKeyboardShow | (payload) => void | — | Fired when keyboard appears | | onKeyboardHide | () => void | — | Fired when keyboard dismisses | | autofocusFirst | boolean | false | Automatically focus the first field on mount (keyboard safe) | | autofocusDelay | number | 500 | Delay in ms before autofocusing (waits for screen transitions) |


<FieldInput>

A drop-in replacement for TextInput. Accepts all standard TextInput props, plus:

| Prop | Type | Default | Description | | ------------------ | ---------------------- | ------- | ---------------------------------------------------------------------------------------------- | | skip | boolean | false | Exclude this field from the auto-focus chain | | nextRef | RefObject<Focusable> | — | Override: focus a specific ref instead of the next detected field | | onFormSubmit | () => void | — | Override: called when this is the last field and Done is tapped | | isAccessoryField | boolean | false | Set to true if this input lives inside keyboardAccessoryView to bypass scroll measurements |


🎹 Keyboard Accessory View

A cross-platform floating toolbar, animated in sync with the keyboard on both iOS and Android.

<FieldForm
  keyboardAccessoryView={
    <View style={styles.toolbar}>
      <TouchableOpacity onPress={Keyboard.dismiss}>
        <Text>Done</Text>
      </TouchableOpacity>
    </View>
  }
  keyboardAccessoryViewMode="whenKeyboardOpen"
>
  <FieldInput placeholder="Message..." />
</FieldForm>

| Mode | Behavior | | ---------------------- | ----------------------------------------------------------------------------------------- | | 'always' (default) | Bar is always visible; slides up when the keyboard opens, back down when it closes | | 'whenKeyboardOpen' | Bar is hidden when the keyboard is closed; fades in and slides up when the keyboard opens |

Animation details: Appearance uses an exponential ease-out curve so the bar settles exactly when the keyboard spring does. Dismissal in always mode uses a subtle spring bounce for a natural gravity-drop feel. Bar height is auto-measured and injected as paddingBottom on the ScrollView so the last field is always reachable.


🪝 Hooks

Two lightweight hooks for when you need keyboard state outside of FieldForm.

import { useKeyboardHeight, useKeyboardVisible } from "react-native-fieldflow";

const height = useKeyboardHeight(); // number — 0 when keyboard is hidden
const visible = useKeyboardVisible(); // boolean

Both hooks use keyboardWillShow / keyboardWillHide on iOS and keyboardDidShow / keyboardDidHide on Android. No polling, no timers.

useFieldFlowController

Exposes imperative actions to control the form from header buttons, tabs, or custom UI outside the field tree.

import { useFieldFlowController } from "react-native-fieldflow";

function HeaderSubmit() {
  const { submit, focusFirst } = useFieldFlowController();

  return <Button title="Submit" onPress={submit} />;
}

| Method | Description | | --------------- | ---------------------------------------------------------------------- | | focusFirst() | Focuses the very first registered field in the form. | | submit() | Triggers onSubmit and optionally dismisses the keyboard. | | scrollTo(ref) | Manually scroll the form to keep a specific Focusable field visible. | | dismiss() | Helper for Keyboard.dismiss(). |


📊 Comparison


🔌 Integrations

React Hook Form

<FieldForm onSubmit={handleSubmit(onSubmit)}>
  <Controller
    control={control}
    name="email"
    render={({ field: { onChange, value, ref } }) => (
      <FieldInput ref={ref} value={value} onChangeText={onChange} />
    )}
  />
</FieldForm>

Bottom Sheets & Custom ScrollViews

Pass a custom scroller (e.g., Gorhom's BottomSheetScrollView) to the ScrollViewComponent prop.

<FieldForm ScrollViewComponent={BottomSheetScrollView}>
  <FieldInput placeholder="Automated chaining inside a bottom sheet!" />
</FieldForm>

Modals & Offset

Adjust keyboardVerticalOffset for navigation headers or modal offsets.

<FieldForm keyboardVerticalOffset={(p) => p === 'ios' ? 44 : 0}>
  <FieldInput />
</FieldForm>

🧪 Example App

An Expo Router example app ships with 11 demo screens covering real-world patterns:

cd example
npx expo start

| Screen | What it demonstrates | | ----------------- | -------------------------------------------- | | Login / Sign-up | Basic focus chaining | | Checkout | Dynamic field skipping with nextRef | | Chat | chatMode + keyboardAccessoryView toolbar | | Long form | RefreshControl + auto-scroll | | Collapsing header | Scroll-linked animated header | | Hooks demo | useKeyboardHeight + useKeyboardVisible | | React Navigation | Header offset handling |


❓ FAQ

Yes. FieldFlow measures the available window height, not screen height, so headers, tab bars, and custom chrome are accounted for automatically. No keyboardVerticalOffset guessing needed.

Wrap it with forwardRef and render FieldInput internally — it's picked up by the chain automatically.

const MyInput = forwardRef<TextInput, MyInputProps>((props, ref) => (
  <View>
    <Text>{props.label}</Text>
    <FieldInput ref={ref} {...props} />
  </View>
));

Yes. Add skip={true} to any FieldInput. The field remains fully functional — it just doesn't participate in Next/Done handling.

Yes. Pass a nextRef to override the auto-detected next field.

const notesRef = useRef<TextInput>(null);

<FieldInput placeholder="Email" nextRef={notesRef} />
<FieldInput placeholder="Phone" skip />
<FieldInput placeholder="Notes" ref={notesRef} />

Yes. FieldFlow uses Animated, Keyboard, and standard event listeners — all fully supported on both the old and new React Native architectures.


🤝 Contributing

Bug reports, feature requests, and pull requests are all welcome.

If you find an edge case — a device, navigation setup, or keyboard type that breaks the chain — please open an issue with a minimal reproduction.


MIT © Syed Sohaib

⭐ Star on GitHub — helps other developers discover this.