Skip to content

Fix empty input accessory button on TextInput without inputAccessoryViewButtonLabel - #59095

Open
jkasprzyk17 wants to merge 1 commit into
react:mainfrom
jkasprzyk17:fix/textinput-empty-accessory-button
Open

jkasprzyk17 wants to merge 1 commit into
react:mainfrom
jkasprzyk17:fix/textinput-empty-accessory-button

Conversation

@jkasprzyk17

@jkasprzyk17 jkasprzyk17 commented Oct 14, 2026 •

Copy link
Copy Markdown

Summary:

Fixes #58952.

With the new architecture, a number-pad TextInput without inputAccessoryViewButtonLabel can show a toolbar with an empty button above the keyboard.

An unset inputAccessoryViewButtonLabel reaches RCTTextInputComponentView as an empty std::string. RCTNSStringFromString("") returns @"", not nil, and setDefaultInputAccessoryView treats any non-nil label as set. The empty string is applied whenever the label goes from set to unset:

  • Recycled view: _props still holds the props of the input the view was recycled from. A new input without a label then diffs "Next" → "" and gets @"". Because prepareForRecycle reset _hasInputAccessoryView, a toolbar with an empty button is created.
  • Label removed: removing the label from a mounted number-pad input sets @"", and the toolbar keeps the old title.

This change maps an empty label to nil with the existing RCTNSStringFromStringNilIfEmpty helper. This matches the old architecture, where the label was an NSString view property and an unset label was nil. The issue suggests clearing the label in prepareForRecycle, but that isn't enough on its own: the diff against the stale _props would still assign @"".

Changelog:

[IOS] [FIXED] - Fix empty input accessory toolbar on a number-pad TextInput without inputAccessoryViewButtonLabel

Test Plan:

Added RCTTextInputComponentViewTests with four cases:

  • a recycled view reused without a label gets no accessory view
  • a recycled view reused without a label falls back to the returnKeyType title
  • a recycled view reused with a label keeps it
  • removing the label removes the accessory view

React/Tests isn't compiled by any open source target, so I couldn't run these tests locally. I did check that the file compiles (-fsyntax-only) with the same clang flags the RNTester build uses for RCTTextInputComponentView.mm.

I tested manually in RNTester (Debug, new architecture, iPhone 17 Pro simulator, iOS 26.5) with this Playground code:

RNTesterPlayground.js
function Playground() {
  const [labelled, setLabelled] = useState(true);
  return (
    <View style={{padding: 10, gap: 8}}>
      <Button
        title={labelled ? 'Swap to unlabelled' : 'Swap to labelled'}
        onPress={() => setLabelled(value => !value)}
      />
      {labelled ? (
        <TextInput
          key="labelled"
          keyboardType="number-pad"
          inputAccessoryViewButtonLabel="Next"
          placeholder='Labelled ("Next")'
        />
      ) : (
        <TextInput
          key="unlabelled"
          keyboardType="number-pad"
          placeholder="Unlabelled"
        />
      )}
    </View>
  );
}

Steps: tap "Swap to unlabelled", then focus the unlabelled input. The new input reuses the recycled view of the labelled one.

Before After
before after

Before: a toolbar with an empty button above the number pad. After: no toolbar. The labelled input still shows "Next". I also removed the label from a focused number-pad input: the toolbar now goes away.

Commands:

yarn install
yarn --cwd packages/react-native-codegen build
cd packages/rn-tester
pod install
pod update hermes-engine --no-repo-update  # Podfile.lock pinned an older Hermes
cd ../..
xcodebuild -workspace packages/rn-tester/RNTesterPods.xcworkspace -scheme RNTester -configuration Debug \
  -destination 'platform=iOS Simulator,id=<iPhone 17 Pro, iOS 26.5 simulator UDID>' build
# ** BUILD SUCCEEDED **
node scripts/clang-format.js --check \
  packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm \
  packages/react-native/React/Tests/Text/RCTTextInputComponentViewTests.mm
# no output, exit code 0

…iewButtonLabel

An unset inputAccessoryViewButtonLabel reaches RCTTextInputComponentView as an
empty string and was applied as @"", which setDefaultInputAccessoryView treats
as a label. A number-pad TextInput reusing a recycled view that had a label, or
whose label was removed, showed a toolbar with an empty button instead of no
toolbar or the returnKeyType title. Map an empty label to nil, as the old
architecture did.

Fixes react#58952
@meta-cla

meta-cla Bot commented Oct 14, 2026

Copy link
Copy Markdown

Hi @jkasprzyk17!

Thank you for your pull request and welcome to our community.

Action Required

In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.

Process

In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.

If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks!

@meta-cla

meta-cla Bot commented Oct 15, 2026

Copy link
Copy Markdown

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 15, 2026
@meta-cla

meta-cla Bot commented Oct 15, 2026

Copy link
Copy Markdown

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 15, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fabric TextInput: prepareForRecycle leaves stale inputAccessoryViewButtonLabel (empty Done bar)

1 participant