Skip to main content

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 and Text 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 to StyleSheet, these properties should all continue to work fine.
  • Is the layout unachievable with the available properties on core components?
    • In this case, reach for StyleSheet and pass it to the style property on the core component.

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({}) vs const 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 of StyleSheet 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 use StyleSheet.
  • 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 or useThemedStyles, you can also combine your dynamic styling within the component style prop:
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} />.