|
| 1 | +# Windows Fabric native components |
| 2 | + |
| 3 | +Use this reference when an agentic component needs a native React Native Windows |
| 4 | +view. It targets the repository's React Native Windows 0.81 line. Verify APIs |
| 5 | +against the installed `react-native-windows` package before adopting guidance |
| 6 | +from a newer RNW branch. |
| 7 | + |
| 8 | +## Decide whether native code is required |
| 9 | + |
| 10 | +Prefer a JavaScript component, slots, and React Native primitives when they can |
| 11 | +meet the contract. Use a Windows Fabric component when the implementation needs |
| 12 | +a Windows-only visual, window, input surface, native API, or performance |
| 13 | +boundary that React Native does not expose. |
| 14 | + |
| 15 | +Establish these facts before editing: |
| 16 | + |
| 17 | +- the installed RNW version; |
| 18 | +- whether the consuming host uses the New Architecture; |
| 19 | +- whether the package must also retain a Paper implementation; |
| 20 | +- whether the surface is a view component, TurboModule, or both; |
| 21 | +- the canonical Windows, Win32, or macOS behavior to preserve. |
| 22 | + |
| 23 | +RNW Fabric components use C++/WinRT and Windows App SDK Composition visuals. |
| 24 | +Do not copy UWP XAML `IViewManager` patterns into the Fabric branch. |
| 25 | + |
| 26 | +## TypeScript native-component specification |
| 27 | + |
| 28 | +Name the schema `<ComponentName>NativeComponent.ts` and keep the component name |
| 29 | +identical in TypeScript, generated code, registration, and the JavaScript |
| 30 | +wrapper. |
| 31 | + |
| 32 | +```ts |
| 33 | +import type { DirectEventHandler, WithDefault } from 'react-native/Libraries/Types/CodegenTypes'; |
| 34 | +import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands'; |
| 35 | +import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; |
| 36 | +import type { ViewProps } from 'react-native'; |
| 37 | + |
| 38 | +type ValueChangedEvent = { |
| 39 | + value: boolean; |
| 40 | +}; |
| 41 | + |
| 42 | +export interface NativeProps extends ViewProps { |
| 43 | + enabled?: WithDefault<boolean, true>; |
| 44 | + onValueChanged?: DirectEventHandler<ValueChangedEvent>; |
| 45 | +} |
| 46 | + |
| 47 | +export interface NativeCommands { |
| 48 | + setValue(viewRef: React.ElementRef<React.ComponentType<NativeProps>>, value: boolean): void; |
| 49 | +} |
| 50 | + |
| 51 | +export const Commands = codegenNativeCommands<NativeCommands>({ |
| 52 | + supportedCommands: ['setValue'], |
| 53 | +}); |
| 54 | + |
| 55 | +export default codegenNativeComponent<NativeProps>('ExampleNativeView'); |
| 56 | +``` |
| 57 | + |
| 58 | +Use React Native codegen types for native values. Extend `ViewProps` for visual |
| 59 | +components. Keep event payloads and commands typed and minimal. |
| 60 | + |
| 61 | +## Windows codegen configuration |
| 62 | + |
| 63 | +Verify the owning package's `codegenConfig`: |
| 64 | + |
| 65 | +```json |
| 66 | +{ |
| 67 | + "codegenConfig": { |
| 68 | + "name": "ExampleSpec", |
| 69 | + "type": "components", |
| 70 | + "jsSrcsDir": "src", |
| 71 | + "includesGeneratedCode": true, |
| 72 | + "windows": { |
| 73 | + "namespace": "ExampleCodegen", |
| 74 | + "generators": ["componentsWindows"], |
| 75 | + "outputDirectory": "windows/Example/codegen", |
| 76 | + "separateDataTypes": true |
| 77 | + } |
| 78 | + } |
| 79 | +} |
| 80 | +``` |
| 81 | + |
| 82 | +Use `"all"` and include `"modulesWindows"` when the package contains both |
| 83 | +TurboModules and components. Run the package's declared codegen command. |
| 84 | +Never edit generated props, event-emitter, registration, or `.g.h` files. |
| 85 | +Persist corrections in the TypeScript schema or codegen configuration. |
| 86 | + |
| 87 | +## C++/WinRT component view |
| 88 | + |
| 89 | +Third-party Fabric components normally derive from the generated CRTP base: |
| 90 | + |
| 91 | +```cpp |
| 92 | +#ifdef RNW_NEW_ARCH |
| 93 | +#include "codegen/react/components/ExampleSpec/ExampleNativeView.g.h" |
| 94 | + |
| 95 | +struct ExampleNativeView |
| 96 | + : winrt::implements<ExampleNativeView, winrt::IInspectable>, |
| 97 | + ExampleCodegen::BaseExampleNativeView<ExampleNativeView> { |
| 98 | + winrt::Microsoft::UI::Composition::Visual CreateVisual( |
| 99 | + winrt::Microsoft::ReactNative::ComponentView const &view) noexcept override; |
| 100 | + |
| 101 | + void Initialize( |
| 102 | + winrt::Microsoft::ReactNative::ComponentView const &view) noexcept override; |
| 103 | + |
| 104 | + private: |
| 105 | + winrt::Microsoft::UI::Composition::SpriteVisual m_visual{nullptr}; |
| 106 | +}; |
| 107 | +#endif |
| 108 | +``` |
| 109 | + |
| 110 | +Implement only the hooks the component needs. Generated registration omits |
| 111 | +unused optional callbacks. |
| 112 | + |
| 113 | +- Create the root Composition visual in `CreateVisual`. |
| 114 | +- Subscribe with `winrt::auto_revoke` and store the revoker. |
| 115 | +- Capture `get_weak()` in event and asynchronous callbacks. |
| 116 | +- Treat view lifecycle callbacks as UI-thread work. |
| 117 | +- Reset reusable native state when the view is recycled. |
| 118 | +- Keep native boundary methods `noexcept`, matching RNW patterns. |
| 119 | + |
| 120 | +The generated CRTP base is not the same as subclassing an RNW built-in |
| 121 | +`ComponentView`. Do not call a nonexistent `Super` method. When subclassing a |
| 122 | +built-in view, preserve its documented base-method ordering. |
| 123 | + |
| 124 | +## Props, events, commands, and state |
| 125 | + |
| 126 | +- Compare old and new props before scheduling visual work. |
| 127 | +- Mark affected visuals dirty in prop updates and batch expensive mutation in |
| 128 | + the final-update hook. |
| 129 | +- Store and null-check the generated event emitter before emitting typed |
| 130 | + payloads. |
| 131 | +- When a built-in base handles commands, call it first and respect `Handled`. |
| 132 | +- Use renderer state only when the renderer must own or measure it. Prefer |
| 133 | + props and events for ordinary controlled interaction state. |
| 134 | + |
| 135 | +The RNW `SwitchComponentView` is the canonical source for interactive props, |
| 136 | +events, commands, pointer input, keyboard input, focus, and UI Automation. |
| 137 | + |
| 138 | +## Layout and Composition visuals |
| 139 | + |
| 140 | +React layout metrics are in device-independent units while Composition visual |
| 141 | +sizes and offsets use physical pixels. Multiply positions and dimensions by |
| 142 | +`PointScaleFactor` before assigning them to visuals or geometries. |
| 143 | + |
| 144 | +Mount and unmount child visuals in renderer order. Backgrounds, borders, |
| 145 | +shadows, transforms, and clipping are normally supplied through |
| 146 | +`ComponentViewFeatures`. Disable a verified feature only when the component |
| 147 | +fully replaces it. |
| 148 | + |
| 149 | +Custom clipping may require disabling native border handling and explicitly |
| 150 | +updating size and offset from layout metrics. Check the target RNW source |
| 151 | +because the feature flags are not exhaustively documented as a public API. |
| 152 | + |
| 153 | +## Theme, input, focus, and accessibility |
| 154 | + |
| 155 | +Native components must support: |
| 156 | + |
| 157 | +- light, dark, and high-contrast updates; |
| 158 | +- platform or Fluent brushes instead of fixed native colors where appropriate; |
| 159 | +- pointer and keyboard input; |
| 160 | +- focus acquisition and focus visuals; |
| 161 | +- React Native accessibility props; |
| 162 | +- a correct UI Automation control type and patterns; |
| 163 | +- UIA property-change notifications for native state changes. |
| 164 | + |
| 165 | +Use Accessibility Insights for Windows or Inspect.exe during initial |
| 166 | +development. Add stable `testID` values to the Storybook validation story so |
| 167 | +automated checks can locate the component through UIA. |
| 168 | + |
| 169 | +## Registration, projects, and autolinking |
| 170 | + |
| 171 | +The complete persistence chain is: |
| 172 | + |
| 173 | +1. Add hand-authored `.h` and `.cpp` files to the library `.vcxproj`. |
| 174 | +2. Add `.vcxproj.filters` entries only for Visual Studio organization. |
| 175 | +3. Leave generated code under the codegen build integration. |
| 176 | +4. Include the component implementation from `ReactPackageProvider.cpp`. |
| 177 | +5. Call the generated `Register<ComponentName>NativeComponent` helper. |
| 178 | +6. Preserve attributed TurboModule registration when the package has modules. |
| 179 | +7. Regenerate or autolink through the consuming app's declared Windows script. |
| 180 | +8. Treat generated autolink files and app solutions as disposable output. |
| 181 | + |
| 182 | +A file on disk but absent from `.vcxproj` is not compiled. |
| 183 | + |
| 184 | +When Fabric and Paper use different component names, generate the Fabric name |
| 185 | +directly and set `paperComponentName` in `codegenNativeComponent`. Callout uses |
| 186 | +the Fabric name `Callout` and the Paper fallback `RCTCallout`; Windows can |
| 187 | +therefore use the generated `RegisterCalloutNativeComponent` helper without |
| 188 | +copying or modifying generated registration code. |
| 189 | + |
| 190 | +## Paper compatibility |
| 191 | + |
| 192 | +When a package intentionally supports both architectures, guard Fabric-only |
| 193 | +headers and implementation with `RNW_NEW_ARCH` and retain the Paper |
| 194 | +`IViewManager` branch separately. Do not share UWP XAML types with WinAppSDK |
| 195 | +Composition code. |
| 196 | + |
| 197 | +| Paper | Fabric | |
| 198 | +| ----------------------------------------- | ------------------------------------------------------ | |
| 199 | +| `IViewManager::CreateView` returning XAML | Generated component base creating a Composition visual | |
| 200 | +| Native property map | Codegen props | |
| 201 | +| `AddViewManager` | Generated Fabric registration helper | |
| 202 | +| XAML child management | Mount and unmount component-view hooks | |
| 203 | +| UWP brushes and geometry | Windows App SDK Composition brushes and geometry | |
| 204 | + |
| 205 | +Test architecture branches in separate compatible hosts. For a |
| 206 | +New-Architecture-only package, remove obsolete Paper code rather than adding an |
| 207 | +untested fallback. |
| 208 | + |
| 209 | +## Validation |
| 210 | + |
| 211 | +Run the smallest declared command at each layer: |
| 212 | + |
| 213 | +1. package format and lint; |
| 214 | +2. TypeScript build for the wrapper and schema; |
| 215 | +3. Windows codegen check; |
| 216 | +4. consuming-app generation or autolink check; |
| 217 | +5. clean native package and app build; |
| 218 | +6. Storybook Windows bundle; |
| 219 | +7. deployed Storybook smoke automation; |
| 220 | +8. interaction and native event assertion; |
| 221 | +9. UIA assertion; |
| 222 | +10. screenshot through the agent host when visual evidence is required; |
| 223 | +11. offline Release smoke after packaging or native dependency changes; |
| 224 | +12. root build after public type, manifest, or project-reference changes. |
| 225 | + |
| 226 | +A successful JavaScript bundle does not validate native code. |
| 227 | + |
| 228 | +## Canonical sources |
| 229 | + |
| 230 | +- [RNW native platform components](https://microsoft.github.io/react-native-windows/docs/native-platform-components) |
| 231 | +- [RNW New Architecture](https://microsoft.github.io/react-native-windows/docs/new-architecture) |
| 232 | +- [RNW Windows codegen CLI](https://microsoft.github.io/react-native-windows/docs/codegen-windows-cli) |
| 233 | +- [RNW native library autolinking](https://microsoft.github.io/react-native-windows/docs/native-platform-using) |
| 234 | +- [RNW NativeModuleSample](https://github.com/microsoft/react-native-windows-samples/tree/main/samples/NativeModuleSample/cpp-lib) |
| 235 | +- [RNW built-in Composition views](https://github.com/microsoft/react-native-windows/tree/main/vnext/Microsoft.ReactNative/Fabric/Composition) |
| 236 | + |
| 237 | +Use the installed dependency or matching release branch first. Treat repository |
| 238 | +head as discovery material until each API is verified against the pinned RNW |
| 239 | +version. |
0 commit comments