Reorganize documentation

Close #1092
Close #1095
This commit is contained in:
Nicolas Gallagher
2018-06-05 10:36:54 -07:00
parent b56a737d62
commit c7c1f29016
13 changed files with 510 additions and 459 deletions
+144
View File
@@ -0,0 +1,144 @@
# Accessibility
On the Web, assistive technologies (e.g., VoiceOver, TalkBack screen readers)
derive useful information about the structure, purpose, and interactivity of
apps from their [HTML elements][html-accessibility-url], attributes, and [ARIA
in HTML][aria-in-html-url]. React Native for Web includes APIs designed to
provide developers with support for making apps more accessible. The most
common and best supported accessibility features of the Web are exposed as the
props: `accessible`, `accessibilityLabel`, `accessibilityLiveRegion`,
`accessibilityRole`, and `importantForAccessibility`.
## Accessibility properties
### accessible
When `true`, indicates that the view is an accessibility element. When a view
is an accessibility element, it groups its children into a single focusable
component. By default, all touchable elements, buttons, and links are
"accessible". Prefer using `accessibilityRole` (e.g., `button`, `link`) to
create focusable HTML elements wherever possible. On web, `accessible={true}`
is implemented using `tabIndex`.
### accessibilityLabel
When a view is marked as `accessible`, it is a good practice to set an
`accessibilityLabel` on the view, so that people who use screen readers know
what element they have selected. On web, `accessibilityLabel` is implemented
using `aria-label`.
```
<TouchableOpacity accessibilityLabel={'Tap me!'} accessible={true} onPress={this._onPress}>
<View style={styles.button}>
<Text style={styles.buttonText}>Press me!</Text>
</View>
</TouchableOpacity>
```
### accessibilityRole
In some cases, we also want to alert the end user of the type of selected
component (i.e., that it is a “button”). To provide more context to screen
readers on the web, you should use the `accessibilityRole` property. (Note that
React Native for Web also provides a compatibility mapping of equivalent
`accessibilityTraits` and `accessibilityComponentType` values to
`accessibilityRole`).
The `accessibilityRole` prop is used to infer an [analogous HTML
element][html-aria-url] and ARIA `role`, where possible. In most cases, both
the element and ARIA `role` are rendered. While this may contradict some ARIA
recommendations, it also helps avoid certain browser bugs, HTML5 conformance
errors, and accessibility anti-patterns (e.g., giving a `heading` role to a
`button` element).
Straight-forward examples:
* `<View accessibilityRole="article" />` => `<article role="article" />`.
* `<View accessibilityRole="banner" />` => `<header role="banner" />`.
* `<Text accessibilityRole="label" />` => `<label />`.
* `<Text accessibilityRole="link" />` => `<a role="link" />`.
* `<View accessibilityRole="main" />` => `<main role="main" />`.
The `heading` role can be combined with `aria-level`:
* `<Text accessibilityRole="heading" />` => `<h1 />`.
* `<Text accessibilityRole="heading" aria-level="3" />` => `<h3 />`.
The `button` role renders an accessible button but is not implemented using the
native `button` element due to some browsers limiting the use of flexbox layout on
its children.
* `<View accessibilityRole="button" />` => `<div role="button" tabIndex="0" />`.
In the example below, the `TouchableHighlight` is announced by screen readers
as a button and it responds to touch, mouse, and keyboard interactions.
```js
<TouchableHighlight accessibilityRole="button" onPress={this._handlePress}>
<View style={styles.button}>
<Text style={styles.buttonText}>Press me!</Text>
</View>
</TouchableHighlight>
```
Note: Avoid changing `accessibilityRole` values over time or after user
actions. Generally, accessibility APIs do not provide a means of notifying
assistive technologies of a `role` value change.
### accessibilityLiveRegion
When components dynamically change we may need to inform the user. The
`accessibilityLiveRegion` property serves this purpose and can be set to
`none`, `polite` and `assertive`. On web, `accessibilityLiveRegion` is
implemented using `aria-live`.
* `none`: Accessibility services should not announce changes to this view.
* `polite`: Accessibility services should announce changes to this view.
* `assertive`: Accessibility services should interrupt ongoing speech to immediately announce changes to this view.
```
<TouchableWithoutFeedback onPress={this._addOne}>
<View style={styles.embedded}>
<Text>Click me</Text>
</View>
</TouchableWithoutFeedback>
<Text accessibilityLiveRegion="polite">
Clicked {this.state.count} times
</Text>
```
In the above example, method `_addOne` changes the `state.count` variable. As
soon as an end user clicks the `TouchableWithoutFeedback`, screen readers
announce text in the `Text` view because of its
`accessibilityLiveRegion="polite"` property.
### importantForAccessibility
The `importantForAccessibility` property controls if a view appears in the
accessibility tree and if it is reported to accessibility services. On web, a
value of `no` will remove a focusable element from the tab flow, and a value of
`no-hide-descendants` will also hide the entire subtree from assistive
technologies (this is implemented using `aria-hidden`).
### Spatial navigation
Focus-based web UIs, e.g., for TVs and Game Consoles can implement [TV remote
control navigation](https://developer.mozilla.org/en-US/docs/Mozilla/Firefox_OS_for_TV/TV_remote_control_navigation)
outside of React using existing directional-focus libraries. Every DOM element
that React Native considers focusable can be matched by the attribute
`data-focusable="true"`.
```js
const focusableElements = document.querySelectorAll('[data-focusable="true"]');
```
### Other
Other ARIA properties can be set via [direct
manipulation](./direct-manipulation.md) or props (this may change in the
future).
[aria-in-html-url]: https://w3c.github.io/aria-in-html/
[html-accessibility-url]: http://www.html5accessibility.com/
[html-aria-url]: http://www.w3.org/TR/html-aria/
+113
View File
@@ -0,0 +1,113 @@
# Experimental / unstable uses
## Use with existing React DOM components
React Native for Web exports a web-specific module called `createElement`,
which can be used to wrap React DOM components. This allows you to use React
Native's accessibility and style optimizations.
In the example below, `Video` will now accept common React Native props such as
`accessibilityLabel`, `accessible`, `style`, and even the Responder event
props.
```js
import { createElement } from 'react-native-web';
const Video = (props) => createElement('video', props);
```
This also works with composite components defined in your existing component
gallery or dependencies ([live example](https://www.webpackbin.com/bins/-KiTSGFw3fB9Szg7quLI)).
```js
import RaisedButton from 'material-ui/RaisedButton';
import { createElement } from 'react-native-web';
import { StyleSheet } from 'react-native';
const CustomButton = (props) => createElement(RaisedButton, {
...props,
style: [ styles.button, props.style ]
});
const styles = StyleSheet.create({
button: {
padding: 20
}
});
```
And `createElement` can be used as drop-in replacement for `React.createElement`:
```js
/* @jsx createElement */
import { createElement } from 'react-native-web';
const Video = (props) => <video {...props} style={[ { marginVertical: 10 }, props.style ]} />
```
Remember that React Native styles are not the same as React DOM styles, and
care needs to be taken not to pass React DOM styles into your React Native
wrapped components.
## Use as a library framework
The React Native (for Web) building blocks can be used to create higher-level
components and abstractions. In the example below, a `styled` function provides
an API inspired by styled-components ([live
example](https://www.webpackbin.com/bins/-KjT9ziwv4O7FDZdvsnX)).
```js
import { createElement } from 'react-native-web';
import { StyleSheet } from 'react-native';
/**
* styled API
*/
const styled = (Component, styler) => {
const isDOMComponent = typeof Component === 'string';
class Styled extends React.Component {
static contextTypes = {
getTheme: React.PropTypes.func
};
render() {
const theme = this.context.getTheme && this.context.getTheme();
const localProps = { ...this.props, theme };
const nextProps = { ...this.props }
const style = typeof styler === 'function' ? styler(localProps) : styler;
nextProps.style = [ style, this.props.style ];
return (
isDOMComponent
? createElement(Component, nextProps)
: <Component {...nextProps} />
);
}
}
return Styled;
}
const styles = StyleSheet.create({
container: {
alignItems: 'center',
backgroundColor: '#2196F3',
flex: 1,
justifyContent: 'center'
}
});
const StyledView = styled(View, styles.container);
```
## Use with react-sketchapp
Use with [react-sketchapp](http://airbnb.io/react-sketchapp/) requires that you
alias `react-native` to `react-sketchapp`. This will allow you to render simple
React Native components in Sketch. Sketch-specific components like `Artboard`
should be imported from `react-sketchapp`.
If you're using `skpm`, you can rely on an [undocumented
feature](https://github.com/sketch-pm/skpm/blob/master/lib/utils/webpackConfig.js)
which will merge your `webpack.config.js`, `.babelrc`, or `package.json` Babel
config into its internal webpack config. The simplest option may be to use the
[babel-plugin-module-alias](https://www.npmjs.com/package/babel-plugin-module-alias)
and configure it in your `package.json`.
+42
View File
@@ -0,0 +1,42 @@
# Client-side rendering
Render apps using `AppRegistry`:
```js
// index.web.js
import App from './src/App';
import React from 'react';
import { AppRegistry } from 'react-native';
// register the app
AppRegistry.registerComponent('App', () => App);
AppRegistry.runApplication('App', {
initialProps: {},
rootTag: document.getElementById('react-app')
});
```
Or render individual components:
```js
import AppHeader from './src/AppHeader';
import React from 'react';
import { render } from 'react-native';
render(<AppHeader />, document.getElementById('react-app-header'))
```
(Components will also be rendered within a tree produced by calling
`ReactDOM.render` (i.e., an existing web app), but
otherwise it is not recommended.)
You might need to adjust the styles of the HTML document's root elements for
your app to fill the viewport.
```html
<html style="height:100%">
<body style="height:100%">
<div id="react-root" style="display:flex;height:100%"></div>
```
+162
View File
@@ -0,0 +1,162 @@
# Direct manipulation
React Native provides several methods to directly access the underlying host
node. This can be useful when you need to make changes directly to a component
without using state/props to trigger a re-render of the entire subtree, or when
you want to focus a view or measure its on-screen dimensions.
The methods described are available on most of the default components provided
by React Native for Web. Note, however, that they are *not* available on the composite
components that you define in your own app.
## Instance methods
**blur**()
Removes focus from an input or view. This is the opposite of `focus()`.
**focus**()
Requests focus for the given input or view. The exact behavior triggered will
depend the type of view.
**measure**(callback: (x, y, width, height, pageX, pageY) => void)
For a given view, `measure` determines the offset relative to the parent view,
width, height, and the offset relative to the viewport. Returns the values via
an async callback.
Note that these measurements are not available until after the rendering has
been completed.
**measureLayout**(relativeToNativeNode: DOMNode, onSuccess: (x, y, width, height) => void)
Like `measure`, but measures the view relative to another view, specified as
`relativeToNativeNode`. This means that the returned `x`, `y` are relative to
the origin `x`, `y` of the ancestor view.
As always, to obtain a native node handle for a component, you can use
`findNodeHandle(component)`.
**measureInWindow**(callback: (x, y, width, height) => void)
Determines the location of the given view in the window and returns the values
via an async callback.
**setNativeProps**(nativeProps: Object)
This function sends props straight to the underlying DOM node.
## About `setNativeProps`
`setNativeProps` is the React Native equivalent to setting properties directly
on a DOM node. Use direct manipulation when frequent re-rendering creates a
performance bottleneck. Direct manipulation will not be a tool that you reach
for frequently.
### `setNativeProps` and `shouldComponentUpdate`
`setNativeProps` is imperative and stores state in the native layer (DOM,
UIView, etc.) and not within your React components, which makes your code more
difficult to reason about. Before you use it, try to solve your problem with
`setState` and `shouldComponentUpdate`.
### Avoiding conflicts with the render function
If you update a property that is also managed by the render function, you might
end up with some unpredictable and confusing bugs because anytime the component
re-renders and that property changes, whatever value was previously set from
`setNativeProps` will be completely ignored and overridden.
### Why use `setNativeProps` on Web?
Using `setNativeProps` in web-specific code is required when making changes to
`className` or `style`, as these properties are controlled by React Native for
Web and setting them directly may cause unintended rendering issues.
```js
setOpacityTo(value) {
this._childElement.setNativeProps({
style: { opacity: value }
})
}
```
### Composite components and `setNativeProps`
Composite components are not backed by a DOM node, so you cannot call
`setNativeProps` on them. Consider this example:
```js
const MyButton = (props) => (
<View>
<Text>{props.label}</Text>
</View>
)
const App = () => (
<TouchableOpacity>
<MyButton label="Press me!" />
</TouchableOpacity>
)
```
If you run this you will immediately see this error: `Touchable` child must
either be native or forward `setNativeProps` to a native component. This occurs
because `MyButton` isn't directly backed by a native view whose opacity should
be set. You can think about it like this: if you define a component with
`React.Component/createClass` you would not expect to be able to set a style
prop on it and have that work - you would need to pass the style prop down to a
child, unless you are wrapping a native component. Similarly, we are going to
forward `setNativeProps` to a native-backed child component.
### Forward `setNativeProps` to a child
All we need to do is provide a `setNativeProps` method on our component that
calls `setNativeProps` on the appropriate child with the given arguments.
```js
class MyButton extends React.Component {
setNativeProps(nativeProps) {
this._root.setNativeProps(nativeProps)
}
render() {
return (
<View ref={component => this._root = component}>
<Text>{this.props.label}</Text>
</View>
)
}
}
```
You can now use `MyButton` inside of `TouchableOpacity`!
### `setNativeProps` to clear `TextInput` value
Another very common use case of `setNativeProps` is to clear the value of a
`TextInput`. For example, the following code demonstrates clearing the input
when you tap a button:
```js
class App extends React.Component {
_handlePress() {
this._textInput.setNativeProps({ text: '' })
}
render() {
return (
<View style={styles.container}>
<TextInput
ref={component => this._textInput = component}
style={styles.textInput}
/>
<TouchableOpacity onPress={this._handlePress.bind(this)}>
<Text>Clear text</Text>
</TouchableOpacity>
</View>
)
}
}
```
+116
View File
@@ -0,0 +1,116 @@
# Getting started
This guide will help you render components and applications with React Native
for Web.
Your application may need to polyfill `Promise`, `Object.assign`, `Array.from`,
and [`ResizeObserver`](https://github.com/que-etc/resize-observer-polyfill) as
necessary for your desired browser support.
If you're not familiar with setting up a new React web project, please follow
the recommendations in the [React documentation](https://reactjs.org/).
## Install
```
yarn add react react-dom react-native-web
```
And if you need to use `ART`:
```
yarn add react-art
```
## Starter kits
Web: [create-react-app](https://github.com/facebookincubator/create-react-app)
includes built-in support for aliasing `react-native-web` to `react-native`.
```
create-react-app my-app
```
Multi-platform: [create-react-native-app](https://github.com/react-community/create-react-native-app)
includes experimental support for Web.
```
create-react-native-app my-app --with-web-support
```
## Configuring a module bundler
If you have a custom setup, you may choose to configure your module bundler to
alias the package to `react-native`.
For example, modify your [webpack](https://github.com/webpack/webpack)
configuration as follows:
```js
// webpack.config.js
module.exports = {
// ...the rest of your config
resolve: {
alias: {
'react-native$': 'react-native-web'
}
}
}
```
Now you can create your components and applications with the React Native API.
## Configuring Babel
If you need to do the aliasing with Babel you can use
[babel-plugin-module-resolver](https://www.npmjs.com/package/babel-plugin-module-resolver)
```
{
"plugins": [
["module-resolver", {
"alias": {
"^react-native$": "react-native-web"
}
}]
]
}
```
## Configuring Jest
[Jest](https://facebook.github.io/jest/) can be configured using the provided
preset. This will map `react-native` to `react-native-web` and provide
appropriate mocks:
```
{
"preset": "react-native-web"
}
```
Please refer to the Jest documentation for more information.
## Configuring Flow
[Flow](https://flow.org) can be configured to understand the aliased module:
```
[options]
module.name_mapper='^react-native$' -> 'react-native-web'
```
You may also need to include a custom libdef
([example](https://gist.github.com/paularmstrong/f60b40d16fc83e1e8e532d483336f9bb))
in your config.
## Other notes
### Safari flexbox performance
Safari prior to version 10.1 can suffer from extremely [poor flexbox
performance](https://bugs.webkit.org/show_bug.cgi?id=150445). The recommended
way to work around this issue (as used on mobile.twitter.com) is to set
`display:block` on Views in your element hierarchy that you know don't need
flexbox layout.
+29
View File
@@ -0,0 +1,29 @@
# Internationalization
To support right-to-left languages, application layout can be automatically
flipped from LTR to RTL. The `I18nManager` API can be used to help with more
fine-grained control and testing of RTL layouts.
## Working with icons and images
Icons and images that must match the LTR or RTL layout of the app need to be manually flipped.
Either use a transform style:
```js
<Image
source={...}
style={{ transform: [{ scaleX: I18nManager.isRTL ? -1 : 1 }] }}
/>
```
Or replace the source asset:
```js
import imageSourceLTR from './back.png';
import imageSourceRTL from './forward.png';
<Image
source={I18nManager.isRTL ? imageSourceRTL : imageSourceLTR}
/>
```
+154
View File
@@ -0,0 +1,154 @@
# Multi-platform applications
## Web-specific code
Minor platform differences can use the `Platform` module.
```js
import { Platform } from 'react-native';
const styles = StyleSheet.create({
height: (Platform.OS === 'web') ? 200 : 100,
});
```
More significant platform differences should use platform-specific files (see
the webpack configuration below for resolving `*.web.js` files):
For example, with the following files in your project:
```
MyComponent.android.js
MyComponent.ios.js
MyComponent.web.js
```
And the following import:
```js
import MyComponent from './MyComponent';
```
React Native will automatically import the correct variant for each specific
target platform.
## Web packaging for existing React Native apps
What follows is merely an _example_ of one basic way to package a web app using
[Webpack](https://webpack.js.org) and [Babel](https://babeljs.io/). (You can
also the React Native bundler, [Metro](https://github.com/facebook/metro), to
build web apps.)
Packaging web apps is subtly different to packaging React Native apps and is
complicated by the need to tree-shake and code-split non-trivial apps.
Install webpack-related dependencies, for example:
```
yarn add --dev babel-loader url-loader webpack webpack-cli webpack-dev-server
```
React Native's Babel preset rewrites ES modules to CommonJS modules, preventing
bundlers from automatically performing "tree-shaking" to remove unused modules
from your web app build. To help with this, you can install the following Babel
plugin:
```
yarn install --dev babel-plugin-react-native-web
```
Create a `web/webpack.config.js` file:
```js
// web/webpack.config.js
const path = require('path');
const webpack = require('webpack');
const appDirectory = path.resolve(__dirname, '../');
// This is needed for webpack to compile JavaScript.
// Many OSS React Native packages are not compiled to ES5 before being
// published. If you depend on uncompiled packages they may cause webpack build
// errors. To fix this webpack can be configured to compile to the necessary
// `node_module`.
const babelLoaderConfiguration = {
test: /\.js$/,
// Add every directory that needs to be compiled by Babel during the build.
include: [
path.resolve(appDirectory, 'index.web.js'),
path.resolve(appDirectory, 'src'),
path.resolve(appDirectory, 'node_modules/react-native-uncompiled')
],
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
// The 'react-native' preset is recommended to match React Native's packager
presets: ['react-native'],
// Re-write paths to import only the modules needed by the app
plugins: ['react-native-web']
}
}
};
// This is needed for webpack to import static images in JavaScript files.
const imageLoaderConfiguration = {
test: /\.(gif|jpe?g|png|svg)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]'
}
}
};
module.exports = {
entry: [
// load any web API polyfills
// path.resolve(appDirectory, 'polyfills-web.js'),
// your web-specific entry file
path.resolve(appDirectory, 'index.web.js')
],
// configures where the build ends up
output: {
filename: 'bundle.web.js',
path: path.resolve(appDirectory, 'dist')
},
// ...the rest of your config
module: {
rules: [
babelLoaderConfiguration,
imageLoaderConfiguration
]
},
resolve: {
// This will only alias the exact import "react-native"
alias: {
'react-native$': 'react-native-web'
},
// If you're working on a multi-platform React Native app, web-specific
// module implementations should be written in files using the extension
// `.web.js`.
extensions: [ '.web.js', '.js' ]
}
}
```
To run in development from the root of your application:
```
./node_modules/.bin/webpack-dev-server -d --config ./web/webpack.config.js --inline --hot --colors
```
To build for production:
```
./node_modules/.bin/webpack -p --config ./web/webpack.config.js
```
Please refer to the Webpack documentation for more information on configuration.
+33
View File
@@ -0,0 +1,33 @@
# Server-side rendering
Server-side rendering to HTML is supported using `AppRegistry`:
```js
import App from './src/App';
import ReactDOMServer from 'react-dom/server';
import { AppRegistry } from 'react-native-web';
// register the app
AppRegistry.registerComponent('App', () => App);
// prerender the app
const { element, getStyleElement } = AppRegistry.getApplication('App', { initialProps });
// first the element
const html = ReactDOMServer.renderToString(element);
// then the styles (optionally include a nonce if your CSP policy requires it)
const css = ReactDOMServer.renderToStaticMarkup(getStyleElement({ nonce }));
// example HTML document string
const document = `
<!DOCTYPE html>
<html style="height:100%">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
${css}
<body style="height:100%; overflow-y:hidden">
<div id="root" style="display:flex; height: 100%">
${html}
</div>
<script nonce="${nonce}" src="${bundlePath}"></script>
`
```
+231
View File
@@ -0,0 +1,231 @@
# Style
React Native relies on JavaScript to define and resolve the styles of your
application. React Native for Web implements the React Native style API in a
way that avoids *all* the [problems with CSS at
scale](https://speakerdeck.com/vjeux/react-css-in-js):
1. No local variables.
2. Implicit dependencies.
3. No dead code elimination.
4. No code minification.
5. No sharing of constants.
6. Non-deterministic resolution.
7. No isolation.
At the same time, it has several benefits:
1. Simple API and expressive subset of CSS.
2. Generates CSS; the minimum required.
3. Good runtime performance.
4. Support for static and dynamic styles.
5. Support for RTL layouts.
6. Easy pre-rendering of critical CSS.
## Defining styles
Styles should be defined outside of the component. Using `StyleSheet.create` is
optional but provides the best performance (by relying on generated CSS
stylesheets). Avoid creating unregistered style objects.
```js
const styles = StyleSheet.create({
heading: {
color: 'gray',
fontSize: '2rem'
},
text: {
marginTop: '1rem',
margin: 10
}
})
```
See the `style` documentation of individual components for supported properties.
NOTE: React Native does not yet support `rem` or `em` units.
## Using styles
All the React Native components accept a `style` property. The value can be a
registered object, a plain object, or an array.
```js
// registered object
<View style={styles.view} />
// plain object
<View style={{ transform: [ { translateX } ] }} />
// array of registered or plain objects
<View style={[ styles.container, this.props.style ]} />
```
The array syntax will merge styles from left-to-right as normal JavaScript
objects, and can be used to conditionally apply styles:
```js
<View style={[
styles.container,
this.state.active && styles.active
]} />
```
When styles are registered with `StyleSheet.create`, the return value is a
number and not a style object. This is important for performance optimizations,
but still allows you to merge styles in a deterministic manner at runtime. If
you need access to the underlying style objects you need to use
`StyleSheet.flatten` (but be aware that this is not the optimized path).
## Composing styles
To let other components customize the style of a component's children you can
expose a prop so styles can be explicitly passed into the component.
```js
class List extends React.Component {
static propTypes = {
style: ViewPropTypes.style,
elementStyle: ViewPropTypes.style,
}
render() {
return (
<View style={this.props.style}>
{elements.map((element) =>
<View style={[ styles.element, this.props.elementStyle ]} />
)}
</View>
);
}
}
```
In another file:
```js
<List style={styles.list} elementStyle={styles.listElement} />
```
You also have much greater control over how styles are composed when compared
to using class names. For example, you may choose to accept a limited subset
of style props in the component's API, and control when they are applied.
## How styles are resolved
React Native style resolution is deterministic and slightly different from CSS.
In the following HTML/CSS example, the `.margin` selector is defined last in
the CSS and takes precedence over the previous rules, resulting in a margin of
`0, 0, 0, 0`.
```html
<style>
.marginTop { margin-top: 10px; }
.marginBottom { margin-bottom: 20px; }
.margin { margin: 0; }
</style>
<div class="marginTop marginBottom margin"></div>
```
But in React Native the most *precise* style property takes precedence,
resulting in margins of `10, 0, 20, 0`.
```js
const style = [
{ marginTop: 10 },
{ marginBottom: 20 },
{ margin: 0 }
];
const Box = () => <View style={style} />
```
## Implementation details
React Native for Web transforms React Native styles into React DOM styles. Any
styles defined using `StyleSheet.create` will ultimately be rendered using CSS
class names.
React Native for Web introduced a novel strategy to achieve this. Each rule is
broken down into declarations, properties are expanded to their long-form, and
the resulting key-value pairs are mapped to unique "atomic CSS" class names.
Input:
```js
const Box = () => <View style={styles.box} />
const styles = StyleSheet.create({
box: {
margin: 0
}
});
```
Output:
```html
<style>
.rn-1mnahxq { margin-top: 0px; }
.rn-61z16t { margin-right: 0px; }
.rn-p1pxzi { margin-bottom: 0px; }
.rn-11wrixw { margin-left: 0px; }
</style>
<div class="rn-156q2ks rn-61z16t rn-p1pxzi rn-11wrixw"></div>
```
This ensures that CSS order doesn't impact rendering and CSS rules are
efficiently deduplicated. Rather than the total CSS growing in proportion to
the number of *rules*, it grows in proportion to the number of *unique
declarations*. As a result, the DOM style sheet is only written to when new
unique declarations are defined and it is usually small enough to be
pre-rendered and inlined.
Class names are deterministic, which means that the resulting CSS and HTML is
consistent across builds important for large apps using code-splitting and
deploying incremental updates.
At runtime registered styles are resolved to DOM style props and memoized.
Any dynamic styles that contain declarations previously registered as static
styles can also be converted to CSS class names. Otherwise, they render as
inline styles.
All this allows React Native for Web to support the rich functionality of React
Native styles (including RTL layouts and `setNativeProps`) while providing one
of the [fastest](https://github.com/necolas/react-native-web/blob/master/packages/benchmarks/README.md),
safest, and most efficient styles-in-JavaScript solutions.
## FAQs
### What about Media Queries?
`StyleSheet.create` is a way of defining the styles your application requires;
it does not concern itself with _where_ or _when_ those styles are applied to
elements.
Media Queries may not be most appropriate for component-based designs. React
Native provides the `Dimensions` API and the component-scoped `onLayout` prop.
If you do choose to use Media Queries, using them in JavaScript via the
`matchMedia` DOM API has the benefit of allowing you to swap out entire
components, not just styles.
### What about pseudo-classes and pseudo-elements?
Pseudo-classes like `:hover` and `:focus` can be implemented with events (e.g.
`onFocus`). Pseudo-elements are not supported; elements should be used instead.
### Do I need a CSS reset?
No. React Native for Web includes a very small CSS reset that removes unwanted
User Agent styles from (pseudo-)elements beyond the reach of React (e.g.,
`html`, `body`) or inline styles (e.g., `::-moz-focus-inner`). The rest is
handled at the component-level.
### What about using Dev Tools?
React Dev Tools supports inspecting and editing of React Native styles. It's
recommended that you rely more on React Dev Tools and live/hot-reloading rather
than inspecting and editing the DOM directly.
+51
View File
@@ -0,0 +1,51 @@
# Web recipes
Examples of how to implement web patterns with React Native.
#### `html` and `body` styles
The `html` and `body` elements require certain styles to support full-screen
React Native apps, and disable "features" like pull-to-refresh in mobile
browsers. Using the `body` as the root scroll view is [not reliably
supported](https://github.com/necolas/react-native-web/issues/829).
[Example code](https://codesandbox.io/s/52x1871vjl).
#### Hover styles
Relying on the web's native hover styles can result in several unwanted UX
consequences. Hover styles might be displayed during touch interactions and can
remain visually "stuck". Furthermore, there's no way to delay or persist hover
for accessibility purposes. This recipe shows how to apply hover styles that
integrate with the Responder event system (e.g., the `Touchable*` press styles)
and display styles *only* when the mouse is active. It can also be used as the
basis for programmatic hover delays and rendering of components (e.g., hover
cards).
[Example code](https://codesandbox.io/s/o9q8vy70l5)
#### Link styles
Cross-platform link components are straight-forward to create and can be
combined with the hover recipe.
[Example code](https://codesandbox.io/s/53r88k5opx)
<!--
#### Typography
Rather than relying on inhereted global typography styles, React Native allows
you to define components that encapsulate a typographic system. This has the
added benefit of enabling content-specific typography adjustments, e.g.,
different font sizes or weights for different languages.
[Example code]()
#### Responsive font size
[Example code]()
#### SVG icons
[Example code]()
-->