diff --git a/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js b/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js
index e896a77f810f16..a335dc62b055c0 100644
--- a/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js
+++ b/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js
@@ -698,6 +698,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = {
inlineImageLeft: true,
editable: true,
fontVariant: true,
+ android_errorMessage: true,
borderBottomRightRadius: true,
borderBottomColor: {process: require('../../StyleSheet/processColor')},
borderRadius: true,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
index c020abdde30129..58b88fa02ee1f1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
@@ -84,7 +84,7 @@ public class ViewProps {
public static final String BACKGROUND_COLOR = "backgroundColor";
public static final String FOREGROUND_COLOR = "foregroundColor";
public static final String COLOR = "color";
- public static final String ERROR_MESSAGE = "errorMessage";
+ public static final String ANDROID_ERROR_MESSAGE = "android_errorMessage";
public static final String FONT_SIZE = "fontSize";
public static final String FONT_WEIGHT = "fontWeight";
public static final String FONT_STYLE = "fontStyle";
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java
index f1591a5fe35d2b..5e618d3549a28c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java
@@ -11,6 +11,7 @@
import android.text.Layout;
import android.text.Spannable;
+import javax.annotation.Nullable;
/**
* Class that contains the data needed for a text update. Used by both and
@@ -30,6 +31,7 @@ public class ReactTextUpdate {
private final int mSelectionStart;
private final int mSelectionEnd;
private final int mJustificationMode;
+ private @Nullable String mErrorMessage;
public boolean mContainsMultipleFragments;
@@ -59,7 +61,8 @@ public ReactTextUpdate(
Layout.BREAK_STRATEGY_HIGH_QUALITY,
Layout.JUSTIFICATION_MODE_NONE,
-1,
- -1);
+ -1,
+ null);
}
public ReactTextUpdate(
@@ -85,7 +88,8 @@ public ReactTextUpdate(
textBreakStrategy,
justificationMode,
-1,
- -1);
+ -1,
+ null);
}
public ReactTextUpdate(
@@ -107,7 +111,8 @@ public ReactTextUpdate(
textBreakStrategy,
justificationMode,
-1,
- -1);
+ -1,
+ null);
}
public ReactTextUpdate(
@@ -122,7 +127,8 @@ public ReactTextUpdate(
int textBreakStrategy,
int justificationMode,
int selectionStart,
- int selectionEnd) {
+ int selectionEnd,
+ @Nullable String errorMessage) {
mText = text;
mJsEventCounter = jsEventCounter;
mContainsImages = containsImages;
@@ -135,6 +141,7 @@ public ReactTextUpdate(
mSelectionStart = selectionStart;
mSelectionEnd = selectionEnd;
mJustificationMode = justificationMode;
+ mErrorMessage = errorMessage;
}
public static ReactTextUpdate buildReactTextUpdateFromState(
@@ -143,15 +150,21 @@ public static ReactTextUpdate buildReactTextUpdateFromState(
int textAlign,
int textBreakStrategy,
int justificationMode,
- boolean containsMultipleFragments) {
+ boolean containsMultipleFragments,
+ @Nullable String errorMessage) {
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(
text, jsEventCounter, false, textAlign, textBreakStrategy, justificationMode);
reactTextUpdate.mContainsMultipleFragments = containsMultipleFragments;
+ reactTextUpdate.mErrorMessage = errorMessage;
return reactTextUpdate;
}
+ public @Nullable String getErrorMessage() {
+ return mErrorMessage;
+ }
+
public Spannable getText() {
return mText;
}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
index 360de688d54849..c8e1b6bd19e6a5 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
@@ -509,6 +509,20 @@ public void maybeSetTextFromJS(ReactTextUpdate reactTextUpdate) {
mIsSettingTextFromJS = false;
}
+ /**
+ * Attempt to set an error message or fail silently. EventCounter is the same one used as with
+ * text.
+ *
+ * @param eventCounter
+ * @param errorMessage
+ */
+ public void maybeSetErrorMessage(int eventCounter, String errorMessage) {
+ if (!canUpdateWithEventCount(eventCounter) || getError() == errorMessage) {
+ return;
+ }
+ setError(errorMessage);
+ }
+
public void maybeSetTextFromState(ReactTextUpdate reactTextUpdate) {
mIsSettingTextFromState = true;
maybeSetText(reactTextUpdate);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index 3c04d1967cd52b..2e58e038b64dff 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -325,7 +325,7 @@ private ReactTextUpdate getReactTextUpdate(
sb.append(TextTransform.apply(text, TextTransform.UNSET));
return new ReactTextUpdate(
- sb, mostRecentEventCount, false, 0, 0, 0, 0, Gravity.NO_GRAVITY, 0, 0, start, end);
+ sb, mostRecentEventCount, false, 0, 0, 0, 0, Gravity.NO_GRAVITY, 0, 0, start, end, null);
}
@Override
@@ -369,11 +369,12 @@ public void updateExtraData(ReactEditText view, Object extraData) {
view.maybeSetTextFromState(update);
view.maybeSetSelection(update.getJsEventCounter(), selectionStart, selectionEnd);
+ view.maybeSetErrorMessage(update.getJsEventCounter(), update.getErrorMessage());
}
}
- @ReactProp(name = ViewProps.ERROR_MESSAGE)
- public void setAndroidErrorMessage(ReactEditText view, String error) {
+ @ReactProp(name = ViewProps.ANDROID_ERROR_MESSAGE)
+ public void setErrorMessage(ReactEditText view, String error) {
view.setError(error);
}
@@ -1325,12 +1326,19 @@ public Object updateState(
int textBreakStrategy =
TextAttributeProps.getTextBreakStrategy(paragraphAttributes.getString("textBreakStrategy"));
+ @Nullable
+ String errorMessage =
+ props.hasKey(ViewProps.ANDROID_ERROR_MESSAGE)
+ ? props.getString(ViewProps.ANDROID_ERROR_MESSAGE)
+ : null;
+
return ReactTextUpdate.buildReactTextUpdateFromState(
spanned,
state.getInt("mostRecentEventCount"),
TextAttributeProps.getTextAlignment(props, TextLayoutManager.isRTL(attributedString)),
textBreakStrategy,
TextAttributeProps.getJustificationMode(props),
- containsMultipleFragments);
+ containsMultipleFragments,
+ errorMessage);
}
}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
index e621e1b585f9be..26e077d523610a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
@@ -246,7 +246,8 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
mTextBreakStrategy,
mJustificationMode,
mSelectionStart,
- mSelectionEnd);
+ mSelectionEnd,
+ null);
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
diff --git a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js
index e12d9ac9eb40d4..3ba638d1eeac7d 100644
--- a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js
+++ b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js
@@ -483,7 +483,7 @@ function ErrorExample(): React.Node {
Type error in the below TextInput to display an error message.
setError('onBlur')}
onEndEditing={() => setError('onEndEditing')}
onChangeText={newText => {