Styling
React GUI relies on JavaScript to define and resolve the styles of your application. The style API avoids all the problems with CSS at scale and produces highly optimized CSS without the need to learn a DSL (e.g., unlike Tailwind CSS).
- No local variables.
- Implicit dependencies.
- No dead code elimination.
- No code minification.
- No sharing of constants.
- Non-deterministic resolution.
- No isolation.
At the same time, it has several benefits:
- Simple API and expressive subset of CSS.
- Generates CSS; the minimum required.
- Good runtime performance.
- Support for static and dynamic styles.
- Support for RTL layouts.
- 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.
const styles = StyleSheet.create({
heading: {
color: 'gray',
fontSize: '2rem'
},
text: {
marginTop: '1rem',
margin: 10
}
})
See the style
documentation of individual components for supported properties.
Using styles #
All the React Native components accept a style
property. The value can be a registered object, a plain object, or an array of objects.
The array syntax will merge styles from left-to-right as normal JavaScript objects, and can be used to conditionally apply styles:
<View style={[
styles.container,
isActive && 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.
export default function List(props) {
return (
<View style={props.style}>
{elements.map((element) =>
<View style={[ styles.element, props.elementStyle ]} />
)}
</View>
);
}
In another file:
<List elementStyle={styles.listElement} style={styles.list} />
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 #
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
.
<style>
.marginTop { margin-top: 10px; }
.marginBottom { margin-bottom: 20px; }
.margin { margin: 0; }
</style>
<div class="marginTop marginBottom margin"></div>
But in React GUI the most precise style property takes precedence, resulting in margins of 10, 0, 20, 0
.
const style = [
{ marginTop: 10 },
{ marginBottom: 20 },
{ margin: 0 }
];
const Box = () => <View style={style} />
Implementation details #
React GUI transforms styles objects into CSS and inline styles. Any styles defined using StyleSheet.create
will ultimately be rendered using CSS class names.
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:
const Box = () => <View style={styles.box} />
const styles = StyleSheet.create({
box: {
margin: 0
}
});
Output:
<style>
.rn-1mnahxq { margin-top: 0px; }
.rn-61z16t { margin-right: 0px; }
.rn-p1pxzi { margin-bottom: 0px; }
.rn-11wrixw { margin-left: 0px; }
</style>
<div class="r-156q2ks r-61z16t r-p1pxzi r-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.
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.
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 GUI 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.