diff --git a/proposals/0000-reduce-fragmentation.md b/proposals/0000-reduce-fragmentation.md new file mode 100644 index 00000000..40609598 --- /dev/null +++ b/proposals/0000-reduce-fragmentation.md @@ -0,0 +1,1153 @@ +--- +title: React DOM for Native +author: +- Nicolas Gallagher +date: 2022-08-03 +updated: 2023-01-31 +--- + +# RFC: React DOM for Native + +## Summary + +This is a proposal to incrementally reduce the API fragmentation faced by developers using React to target multiple platforms via code shared between native and web. The proposed cross-platform user interface APIs are a subset of existing web standards for DOM, CSS, and HTML - "Strict DOM". The proposed changes are overwhelmingly additive and do not require migration of existing React Native UI code (deprecations are optional / follow up work). Incremental progress can help to reduce the fragmentation between React Native and React DOM components, while the ability to run React DOM code (with minor modifications) on native is a longer-term goal. + +## Motivation + +React Native currently includes many APIs that are modelled on Web APIs but do not conform to the standards of those Web APIs. React Native also includes many APIs that achieve the same results on Android and iOS but are exposed as 2 different props. And React Native includes several APIs that have known performance (network and runtime) drawbacks on Web. + +This proposal aims to allow developers to target more platforms with cross-platform APIs, and deliver better performance when targeting browsers. Features for Android, iOS, and Web are unified by aligning with the Web standard. Supporting standards helps to: + +* minimize the overhead when running in browsers; +* reduce developer education required to learn features; +* set clear and cohesive API end-state expectations for contributors to aim for; +* accelerate the framework's development by avoiding API design costs; +* support backwards compatibility; +* develop universal codebases. + +The existing solution for targeting web with React Native is to use React Native for Web. React Native for Web is a user-space library built on top of React DOM and native DOM APIs. It shims React Native components and APIs on the web. The tooling for an existing React DOM app simply maps the 'react-native' export to 'react-native-web'. + +![](https://user-images.githubusercontent.com/239676/205388174-6fce19f1-8b3a-4c6e-82f1-89ef9c21ab7d.png) + +This is the most complete and widely used shim, but comes with considerable DX and UX costs on the web. The shim must implement a large surface area of fragmented APIs, and it needs to modify standard APIs and objects (e.g., events) to match React Native's non-standard implementations. + +In contrast, implementing a "Strict DOM" subset in React Native shifts the weight of bridging native and web apps onto React Native, where it can be done most efficiently. Although React Native will not support all the features available on web, it will still support a greater expanded feature set relative to React Native today. On the web, we would only need to combine React DOM with a white-label CSS compiler like stylex. + +![](https://user-images.githubusercontent.com/239676/205388313-e58f8793-51cd-4a6e-86e7-89425fd2d0e1.png) + +## Detailed design + +The "complete" API involved is broken down into the following sections. + +* [Environment API](#environment-api). Global APIs to add to the host environment. +* [Elements API](#elements-api-dom-subset). DOM APIs to add to host component instances. +* [Components API](#components-api-dom-subset). React DOM components to add to React Native. +* [Props API](#props-api-react-dom-subset). React DOM component props to add to new components, and existing React Native components as part of an incremental strategy. +* [Styling API](#styles-api-css-subset). CSS APIs to add to the React Native environment. + +A simplified example of the user-space code we'd aim to support is as follows: + +```js +import { html, css } from 'react-native/dom'; + +export function VStackPanel(props) { + const connectedCallback = function (node) { + const handler = () => { + const { offsetWidth } = e.target; + // ... + }; + const options = { capture: true }; + node.addEventListener('pointerdown', handler, options); + return function disconnected() { + node.removeEventListener('pointerdown', handler, options) + } + }; + + return ( + // Use HTML element + + ) +} +``` + +But there are many incremental steps that can be taken along the way. + +## Implementation and adoption strategy + +The proposal is to support both an incremental adoption strategy, as well as a separate "React DOM" bindings exports. The incremental strategy would find ways to align existing APIs in React Native with their React DOM equivalents, and gradually deprecate the non-standard APIs. Whereas the separate bindings export would be designed to provide most of what is needed for a direct compatibility layer with React DOM. + +This would ensure a significant amount of overlap between the existing React Native components and the dedicated "React DOM" compatibility API, allowing for co-mingling of code and reduced developer education. There is no suggestion of deprecating the current React Native components and APIs at this stage. + +### Reduce API fragmentation across platforms + +The initial step is to incrementally reduce existing API fragmenetation across platforms. This involves consolidating the different props, styles, and events for similar functionality across different platforms. The APIs that we consolidate upon are the W3C standards, as React Native is already fairly closely aligned with these standards. + +Doing this will make it easier for web developers to work with React Native's existing components and related APIs. This is the path for developers to gradually migrate their existing React Native code into a form that is more aligned with the web. And it will allow React Native for Web to be smaller and faster, providing better results on web via the existing tools that developers use today. + +One example of this kind of incremental change is to map props in the existing core components (i.e., `View`, `Text`, etc.) to the W3C equivalents: `id` to `nativeID`, `aria-label` to `accessibilityLabel`, and so on. React Native for Web currently "owns" this translation step, but we would instead move it into React Native to claw back performance on web. For developers familiar with React DOM, there will be less of a learning curve to applying that knowledge to React Native. + +```jsx + +``` + +```jsx +Alternative text +``` + +```jsx +