- Support for single, multiple, and compound variants without any runtime overhead
- Runtime or compile-time style generation using a babel plugin
- Typescript support with variant autocompletion as a property
- Drop-in replacement for StyleSheet
There are many alternatives that allow you to build your components using JSX and props. We're not going to argue that it's easy to create components in this way because it certainly is. However, exposing those props comes with a cost.
What should be a solution for styling ends up becoming a performance problem. Each component you use from these libraries ends up generating dozens of operations, merging objects at runtime, and significantly impacting rendering time. Checking this problem is as easy as choosing your favorite library, selecting a handful of components, and measuring their rendering time.
Fortunately, there is a solution to easily handle variants and themes in React Native, and that is to generate styles at compile-time. Using the styled HOC from this library, you can generate styles for different variants of your components without adding any runtime overhead. In fact, the resulting code can be more efficient than using statically created styles with StyleeSheet.create()
.
yarn add @fast-styles/react
or
npm install @fast-styles/react --save
This example creates a ButtonRoot component from a touchable and defines the type
variant to change the button color.
const ButtonRoot = styled(TouchableOpacity, {
// base styles
display: "flex",
alignItems: "center",
justifyContent: "center",
height: 40,
width: "100%",
maxWidth: 200,
borderRadius: 20,
// variants
variants: {
coloScheme: {
primary: {
positive: "green",
},
negative: {
backgroundColor: "red",
},
disabled: {
backgroundColor: "gray",
},
},
},
});
const Button = (props) => {
return (
<ButtonRoot colorScheme={"positive"} onPress={props.onPress}>
{props.children}
</ButtonRoot>
);
};
When needing to set styles for a variant based on a combination of other variants, you can create a rule for compound variants using the + sign.
const ButtonRoot = styled(TouchableOpacity, {
display: "flex",
alignItems: "center",
justifyContent: "center",
variants: {
type: {
solid: {},
outline: {
backgroundColor: "transparent",
borderWidth: 3,
},
},
colorScheme: {
primary: {},
negative: {},
disabled: {},
},
},
compoundVariants: {
"solid+primary": {
backgroundColor: "green",
},
"solid+negative": {
backgroundColor: "red",
},
"solid+disabled": {
backgroundColor: "gray",
},
"outline+primary": {
borderColor: "green",
},
"outline+negative": {
borderColor: "red",
},
"outline+disabled": {
borderColor: "gray",
},
},
});
The styled
HOC generates a map with all possible combinations for each variant.
const Button = styled(TouchableOpacity, {
variants: {
colorScheme: {
primary: {
/* small styles */
},
secondary: {
/* small styles */
},
},
size: {
small: {
/* small styles */
},
medium: {
/* medium styles */
},
large: {
/* large styles */
},
},
},
});
For example, if a button component has a variant called type
that offers options like primary
and secondary
, and it has another variant called size
that offers options like small
, medium
, and large
, applying the styled HOC will generate a map like this:
const buttonStyles = {
"primary+small": {
/* combined styles */
},
"primary+medium": {
/* combined styles */
},
"primary+large": {
/* combined styles */
},
"secondary+small": {
/* combined styles */
},
"secondary+medium": {
/* combined styles */
},
"secondary+large": {
/* combined styles */
},
};