General Styling, Component Library and Styled Components
IMPORTANT: Much of this may change as we introduce the new UI kit through Storybook.
There are a number of ways to approach styling components and screens within the codebase, and some things to consider when starting from scratch on something.
We currently have a fairly substantial component library which comprises of a number of "foundational" building block components that can be used to achieve layouts and styles required in your work. They are for the most part built using styled-components
, and expose a large number of props which allow you to achieve the majority of your styling.
Recent performance auditing found that styled-components introduced a not-insignificant performance drain on the app, so as a result we are trying to reduce the amount of new instances of styled-components. Using existing styled-components is fine, but no new declarations (e.g. const Container = styled.View()
) should be occurring. We plan to move all core components to StyleSheet
in the future.
When building new features, consider the following:
- Can the design be achieved with existing components and their available props? .
- If, for example, you were creating a box with some text and a button in it, can that be done with the existing
Box
,Button
andText
components? Each of them accept padding, margins and other common style properties through their props and so this layout should be achievable with them. There is no need to wrap them in styled-components i.e.const Component = styled(Box)()
. Because these components won't change in the way they are implemented once we swap toStyleSheet
, these properties should all continue to work fine.
- If, for example, you were creating a box with some text and a button in it, can that be done with the existing
- Is the layout unachievable with the available properties on core components?
- In this case, reach for
StyleSheet
and pass it to thestyle
property on the core component.
- In this case, reach for
Theming and dynamic styling within StyleSheet
Declaring a static StyleSheet
object is simple enough:
const styles = StyleSheet.create({
container: {
backgroundColor: "red",
paddingBottom: 10,
},
});
But styles usually require access to the app themes, as well as dynamic styling. If you only require dynamic properties, the StyleSheet
can be declared as a function that receives those properties, and returns a StyleSheet
:
const stylesFn = (params: { noPadding?: boolean; pinkBackground?: boolean }) =>
StyleSheet.create({
container: {
backgroundColor: params.pinkBackground ? "pink" : "red",
paddingBottom: params.noPadding ? 0 : 10,
},
});
If the styles requires access to the theme then use the useThemedStyles
with a styles object like above, and it will then have access to the theme:
import { useThemedStyles } from "@app/hooks/useThemedStyles";
const stylesFn = (theme: Theme) =>
StyleSheet.create({
container: {
backgroundColor: theme.backgroundColor,
},
});
const Component = () => {
const { styles, theme } = useThemedStyles(stylesFn);
return <></>;
};
The theme object should not be imported and used directly when styling components. useTheme
and useThemedStyles
both use the ThemeContext
, meaning they apply any theming to styles and are reactive to changes.
/* INCORRECT */
import { theme } from "@app/theme";
const Component = () => {
return <Box borderColor={theme.orange} />;
};
/* CORRECT */
import { useTheme } from "@app/hooks";
const Component = () => {
const theme = useTheme();
return <Box borderColor={theme.orange} />;
};
Other points:
- Should I use
StyleSheet
or just a plain JS object?const styles = StyleSheet.create({})
vsconst styles = {}
.- There is no real difference between the two. The RN team proposed performance enhancements with
StyleSheet
but they never went anywhere. The main benefit ofStyleSheet
is not having to manually type it, which is reason enough to prefer it, but also for the sake of consistency and having a standard we prefer to useStyleSheet
.
- There is no real difference between the two. The RN team proposed performance enhancements with
- Where should I declare my
StyleSheet
?- Styles should be declared in the outer scope of the file, outside of the component.
- How do I dynamically apply styles based on props or state?
- Using either
StyleSheet
oruseThemedStyles
, you can also combine your dynamic styling within the componentstyle
prop:
- Using either
const Component = ({ isActive }) => {
const { styles, theme } = useThemedStyles(stylesFn);
return (
<Box
style={[
styles.containerStyle,
{ borderColor: isActive ? "green" : "red" },
]}
>
<Text style={[styles.textStyle, { color: isActive ? "green" : "red" }]}>
Example Text
</Text>
</Box>
);
};
const stylesFn = (theme?: Theme) =>
StyleSheet.create({
containerStyle: {
flexDirection: "row",
justifyContent: "flex-start",
},
textStyle: {
fontSize: 666,
marginLeft: 5,
},
});
- I want a named component -
<FancyContainer />
instead of<Box style={styles.fancyContainer} />
.- If you have a good reason for doing this, then it can be achieved by just declaring a new React component as you would any other:
const FancyContainer = (props: Props) => <Box style={styles.fancyContainer} />
.
- If you have a good reason for doing this, then it can be achieved by just declaring a new React component as you would any other: