Commit 4d114df
fix(fabric): textInput text color not adapting to appearance changes (#2913)
## Summary
- Fixes TextInput text color not updating when the system appearance
changes (light ↔ dark mode) on the new architecture (Fabric)
- Ensures the default text color (`labelColor`) is always set on macOS,
since `NSAttributedString` defaults to black unlike iOS
- Adds `viewDidChangeEffectiveAppearance` (macOS) and
`hasDifferentColorAppearanceComparedToTraitCollection:` (iOS) handlers
to refresh text attributes on appearance change
## Root Cause
Three interrelated issues on macOS Fabric:
1. **Missing foreground color**: `RCTNSTextAttributesFromTextAttributes`
skipped setting `NSForegroundColorAttributeName` when no explicit
`color` prop or `opacity` was set. On macOS, `NSAttributedString`
defaults to black (unlike iOS where `UITextField` provides its own
dynamic default), making text invisible in dark mode.
2. **No appearance change handler**: `RCTTextInputComponentView` had no
`viewDidChangeEffectiveAppearance` override on macOS, so
`defaultTextAttributes` were never refreshed when switching light/dark
mode.
3. **Frozen dynamic colors**: The C++ color pipeline resolves dynamic
colors (like `labelColor`) to static values at creation time. Simply
re-calling `RCTNSTextAttributesFromTextAttributes` after an appearance
change returns the same stale color. The fix detects when the foreground
color is the default semantic `labelColor` (vs. a user-specified color)
and replaces it with a fresh `[NSColor labelColor]`, then re-applies the
attributed text while suppressing React state reconciliation.
## Test plan
- [ ] Launch RNTester macOS in dark mode → TextInput with no `color`
prop shows visible text
- [ ] Toggle to light mode → text color adapts (dark text on light
background)
- [ ] Toggle back to dark mode → text color adapts (light text on dark
background)
- [ ] TextInput with explicit `color` prop (e.g. `"red"`, `"white"`)
preserves its color across appearance changes
- [ ] Both single-line and multiline TextInput work correctly
- [ ] Newly typed text after appearance change uses the correct color
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>1 parent d25b8c9 commit 4d114df
File tree
2 files changed
+48
-1
lines changed- packages/react-native
- ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager
- React/Fabric/Mounting/ComponentViews/TextInput
2 files changed
+48
-1
lines changedLines changed: 37 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
169 | 169 | | |
170 | 170 | | |
171 | 171 | | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
172 | 196 | | |
173 | 197 | | |
174 | 198 | | |
| |||
182 | 206 | | |
183 | 207 | | |
184 | 208 | | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
185 | 221 | | |
186 | | - | |
| 222 | + | |
187 | 223 | | |
188 | 224 | | |
189 | 225 | | |
| |||
Lines changed: 11 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
146 | 146 | | |
147 | 147 | | |
148 | 148 | | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
149 | 155 | | |
| 156 | + | |
150 | 157 | | |
151 | 158 | | |
152 | 159 | | |
| |||
158 | 165 | | |
159 | 166 | | |
160 | 167 | | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
161 | 171 | | |
| 172 | + | |
162 | 173 | | |
163 | 174 | | |
164 | 175 | | |
| |||
0 commit comments