From 600d45bf847a322e2b071f36a079c6535a054279 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Sun, 29 Mar 2026 22:37:53 -0500 Subject: [PATCH 1/2] fix(fabric): Switch default Text color to labelColor --- packages/react-native/Libraries/Text/RCTTextAttributes.mm | 2 +- .../Libraries/Text/TextInput/Multiline/RCTUITextView.mm | 2 +- .../Libraries/Text/TextInput/RCTBaseTextInputView.mm | 2 +- .../react/renderer/attributedstring/TextAttributes.cpp | 5 ++++- .../renderer/textlayoutmanager/RCTAttributedTextUtils.mm | 5 ++++- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/react-native/Libraries/Text/RCTTextAttributes.mm b/packages/react-native/Libraries/Text/RCTTextAttributes.mm index e3f9a0af583e..2ee06afd37bb 100644 --- a/packages/react-native/Libraries/Text/RCTTextAttributes.mm +++ b/packages/react-native/Libraries/Text/RCTTextAttributes.mm @@ -277,7 +277,7 @@ - (CGFloat)effectiveFontSizeMultiplier - (RCTPlatformColor *)effectiveForegroundColor // [macOS] { - RCTPlatformColor *effectiveForegroundColor = _foregroundColor ?: [RCTPlatformColor blackColor]; // [macOS] + RCTPlatformColor *effectiveForegroundColor = _foregroundColor ?: [RCTTextAttributes defaultForegroundColor]; // [macOS] if (!isnan(_opacity)) { effectiveForegroundColor = diff --git a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm index 8c71181b26a8..c5ae3fe6ed07 100644 --- a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +++ b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm @@ -69,7 +69,7 @@ - (instancetype)initWithFrame:(CGRect)frame _textInputDelegateAdapter = [[RCTBackedTextViewDelegateAdapter alloc] initWithTextView:self]; self.backgroundColor = [RCTPlatformColor clearColor]; // [macOS] - self.textColor = [RCTPlatformColor blackColor]; // [macOS] + self.textColor = [RCTPlatformColor labelColor]; // [macOS] // This line actually removes 5pt (default value) left and right padding in UITextView. #if !TARGET_OS_OSX // [macOS] self.textContainer.lineFragmentPadding = 0; diff --git a/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm b/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm index 572bf21ef4a3..188ddf034750 100644 --- a/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm +++ b/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm @@ -127,7 +127,7 @@ - (void)enforceTextAttributesIfNeeded NSDictionary *textAttributes = [[_textAttributes effectiveTextAttributes] mutableCopy]; if ([textAttributes valueForKey:NSForegroundColorAttributeName] == nil) { - [textAttributes setValue:[RCTPlatformColor blackColor] forKey:NSForegroundColorAttributeName]; // [macOS] + [textAttributes setValue:[RCTPlatformColor labelColor] forKey:NSForegroundColorAttributeName]; // [macOS] } backedTextInputView.defaultTextAttributes = textAttributes; diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp index 2982e5923693..11ef6dea0ee1 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp @@ -178,7 +178,10 @@ TextAttributes TextAttributes::defaultTextAttributes() { static auto textAttributes = [] { auto textAttributes = TextAttributes{}; // Non-obvious (can be different among platforms) default text attributes. - textAttributes.foregroundColor = blackColor(); + // [macOS textAttributes.foregroundColor = blackColor(); + // Leave foregroundColor unset so each platform can apply a dynamic default + // (e.g. labelColor) that adapts to light/dark mode. + // macOS] textAttributes.backgroundColor = clearColor(); textAttributes.fontSize = 14.0; textAttributes.fontSizeMultiplier = 1.0; diff --git a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm index 5ff1c376da8b..d4d6e260efc3 100644 --- a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm +++ b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm @@ -144,7 +144,7 @@ inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const Tex inline static RCTPlatformColor *RCTEffectiveForegroundColorFromTextAttributes(const TextAttributes &textAttributes) // [macOS] { - RCTPlatformColor *effectiveForegroundColor = RCTUIColorFromSharedColor(textAttributes.foregroundColor) ? RCTUIColorFromSharedColor(textAttributes.foregroundColor) : [RCTPlatformColor blackColor]; // [macOS] + RCTPlatformColor *effectiveForegroundColor = RCTUIColorFromSharedColor(textAttributes.foregroundColor) ?: [RCTPlatformColor labelColor]; // [macOS] if (!isnan(textAttributes.opacity)) { effectiveForegroundColor = [effectiveForegroundColor @@ -182,6 +182,9 @@ inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const Tex if (textAttributes.foregroundColor || !isnan(textAttributes.opacity)) { attributes[NSForegroundColorAttributeName] = effectiveForegroundColor; + } else { + // [macOS] Apply dynamic default (labelColor) so text adapts to dark mode + attributes[NSForegroundColorAttributeName] = effectiveForegroundColor; } if (textAttributes.backgroundColor || !isnan(textAttributes.opacity)) { From 241ebeb3042ff4f57b8294d8ea5ec06c131f4559 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Mon, 30 Mar 2026 17:26:12 -0500 Subject: [PATCH 2/2] add `defaultForegroundTextColor()` --- .../renderer/attributedstring/TextAttributes.cpp | 5 +---- .../ReactCommon/react/renderer/graphics/Color.h | 1 + .../ios/react/renderer/graphics/HostPlatformColor.mm | 11 +++++++++++ .../textlayoutmanager/RCTAttributedTextUtils.mm | 3 --- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp index 11ef6dea0ee1..f042d94777e6 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp @@ -178,10 +178,7 @@ TextAttributes TextAttributes::defaultTextAttributes() { static auto textAttributes = [] { auto textAttributes = TextAttributes{}; // Non-obvious (can be different among platforms) default text attributes. - // [macOS textAttributes.foregroundColor = blackColor(); - // Leave foregroundColor unset so each platform can apply a dynamic default - // (e.g. labelColor) that adapts to light/dark mode. - // macOS] + textAttributes.foregroundColor = defaultForegroundTextColor(); // [macOS] textAttributes.backgroundColor = clearColor(); textAttributes.fontSize = 14.0; textAttributes.fontSizeMultiplier = 1.0; diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/Color.h b/packages/react-native/ReactCommon/react/renderer/graphics/Color.h index 5c2dd9aa509b..6fed98d9d9e7 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/Color.h +++ b/packages/react-native/ReactCommon/react/renderer/graphics/Color.h @@ -70,6 +70,7 @@ SharedColor colorFromRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a); SharedColor clearColor(); SharedColor blackColor(); SharedColor whiteColor(); +SharedColor defaultForegroundTextColor(); // [macOS] #ifdef RN_SERIALIZABLE_STATE inline folly::dynamic toDynamic(const SharedColor& sharedColor) { diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.mm b/packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.mm index ed55f28aa664..15395d0b70fe 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.mm +++ b/packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.mm @@ -10,6 +10,7 @@ #import #import // [macOS] #import +#import // [macOS] #import #import #import @@ -342,6 +343,16 @@ int32_t ColorFromUIColor(const std::shared_ptr &uiColor) return Color(wrapManagedObject(semanticColor)); } +// [macOS +SharedColor defaultForegroundTextColor() { + static SharedColor color = [] { + std::vector items = {"labelColor"}; + return SharedColor(Color::createSemanticColor(items)); + }(); + return color; +} +// macOS] + } // namespace facebook::react NS_ASSUME_NONNULL_END diff --git a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm index d4d6e260efc3..207a5f044e0e 100644 --- a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm +++ b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm @@ -182,9 +182,6 @@ inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const Tex if (textAttributes.foregroundColor || !isnan(textAttributes.opacity)) { attributes[NSForegroundColorAttributeName] = effectiveForegroundColor; - } else { - // [macOS] Apply dynamic default (labelColor) so text adapts to dark mode - attributes[NSForegroundColorAttributeName] = effectiveForegroundColor; } if (textAttributes.backgroundColor || !isnan(textAttributes.opacity)) {