Skip to content

underlineColorAndroid silently ignored on initial render with Fabric (New Architecture) #57921

Description

@HADeveloper

Description

On Android with the New Architecture (Fabric), underlineColorAndroid set as a prop on TextInput is silently dropped on the initial render. The dark material underline remains visible. The prop applies correctly after any subsequent re-render (state change, hot reload).

React Native version: 0.83.x (first version where this is unavoidable — Expo SDK 55 made Fabric mandatory)
Platform: Android only
Architecture: New Architecture (Fabric) only — did not reproduce on Paper/Bridge

Steps to reproduce

<TextInput underlineColorAndroid="transparent" />

On initial mount: the native Android underline is visible.
After any re-render: the underline disappears correctly.

Expected behavior

underlineColorAndroid is applied on initial mount, consistent with the old architecture behavior.

Actual behavior

The prop is silently dropped on initial mount. The ReactEditText shows its default material underline.

Root cause

ReactTextInputManager.kt, setUnderlineColor (unchanged between 0.82 and 0.83):

@ReactProp(name = "underlineColorAndroid", customType = "Color")
public fun setUnderlineColor(view: ReactEditText, underlineColor: Int?) {
    val background = view.background

    if (background == null) {
      return  // ← prop silently dropped if background not yet populated
    }
    // ...
}

In Fabric, createViewInstance creates the ReactEditText and immediately applies all initial props synchronously. If the view's background drawable is null at that moment (no material theme on the ThemedReactContext, or editTextBackground attr not resolved yet), setUnderlineColor hits the early return and the prop is lost.

A secondary issue: if BackgroundStyleApplicator.setBackgroundColor() runs first, it wraps the original background in a CompositeBackgroundDrawable (LayerDrawable). Calling setColorFilter on a LayerDrawable does not propagate to child drawables in all Android versions, so the underline drawable inside the wrapper is unaffected.

On the update path (re-render), the background is already populated and the color filter applies successfully — which is why subsequent renders work.

Workaround

Call setNativeProps({ underlineColorAndroid }) in a useEffect after mount, which goes through the update path:

const ref = useRef<TextInput>(null)

useEffect(() => {
  ref.current?.setNativeProps({ underlineColorAndroid: 'transparent' })
}, [])

<TextInput ref={ref} underlineColorAndroid="transparent" />

Suggested fix

In setUnderlineColor, rather than silently returning when background == null, ensure the background drawable is initialized before applying the color filter — either by calling ensureCompositeBackgroundDrawable(view) or by initializing a default background from the EditText theme attribute.

Activity

  1. react-native-bot commented on Aug 12, 2026

    @react-native-bot
    Collaborator

    Warning

    Missing reproducer: We could not detect a reproducible example in your issue report. Reproducers are mandatory and we can accept only one of those as a valid reproducer:


    You can read more about about it on our website: How to report a bug.

  2. nduaarte commented on Aug 14, 2026

    @nduaarte
    Contributor

    Edit: I spent more time on this and want to walk back my previous comment — I haven't been able to reproduce the bug.

    I built RNTester from current main and tested on a real device/emulator (API 36, Fabric enabled), using both a bare <TextInput underlineColorAndroid="..." /> and one with an explicit borderWidth/borderColor (to force the CompositeBackgroundDrawable wrap before setUnderlineColor runs). In every case — cold app start included — the underline color applied correctly on the very first mount.

    I also added temporary logging directly inside setUnderlineColor/createViewInstance: view.background was never null at the point the prop setter runs (AppCompatEditText resolves its themed background synchronously in its own constructor), and the color filter did propagate through the CompositeBackgroundDrawable/LayerDrawable wrapper when present. So neither of the two root causes described above reproduced for me.

    Since this report is also missing the mandatory reproducer (flagged by the bot above), would you be able to share:

    • The exact Android OS version/API level and device (physical vs. emulator) where you see this
    • A minimal repro via a RNTesterPlayground.js PR or an Expo Snack

    Happy to take another look once there's something concrete to reproduce against.


    Original comment below, kept for context:

    Hi! I did some digging into this and I believe your root-cause analysis is spot on, the early return in setUnderlineColor when background == null on the initial mount path definitely looks like the culprit, and the LayerDrawable/setColorFilter propagation issue you flagged as a secondary cause makes sense too.

    I'd like to take a shot at implementing your suggested fix (ensuring the background drawable is initialized before applying the color filter, handling both the plain-background case and the CompositeBackgroundDrawable case). I have a full RN + Fabric dev environment set up and can reproduce this reliably with the repro you provided.

    Would it be okay if I open a PR for this? Happy to adjust the approach based on any feedback first if you'd prefer.

  3. react-native-bot commented on Sep 8, 2026

    @react-native-bot
    Collaborator

    This issue is waiting for author's feedback since 24 days. Please provide the requested feedback or this will be closed in 7 days.

  4. added
    StaleThere has been a lack of activity on this issue and it may be closed soon.
    on Sep 8, 2026
  5. react-native-bot commented on Sep 15, 2026

    @react-native-bot
    Collaborator

    This issue was closed because the author hasn't provided the requested feedback after 7 days.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs: Author FeedbackNeeds: ReproThis issue could be improved with a clear list of steps to reproduce the issue.StaleThere has been a lack of activity on this issue and it may be closed soon.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions