Styled Components for React Native the way they should have been.
Inspired by this article
Why π styled-rn
it better than π
πΌ styled-components/native
?
Well, first of all, using styled components should be fun, but using css to style a React Native app is cumbersome and often ends up to be very messy.
Also:
styled-rn
gives you access to ALL React Native style propsstyled-rn
is faster because it does not do tedious string template processingstyled-rn
is easier to use (again, no messy string templates)styled-rn
is fully typed and has a nice APIstyled-rn
supports custom props, theme viaThemeProvider
, multiple style objects and more..styled-rn
has a shorter name ;)
npm i styled-rn
Styled-RN depends on react-native-safe-area-context to provide insets for the ctx
prop. See below for more details.
npm i react-native-safe-area-context
import { styled } from "styled-rn";
// Basic usage
export const Container = styled.View({
flexDirection: "row",
backgroundColor: "cyan",
});
// Use with any component
export const CoolAndBoldComponent = styled(CoolComponent, {
fontWeight: "bold",
});
// Pass props to the styled component (attrs)
export const NonWrappingText = styled.Text(
{
color: "blue",
},
{
attrs: {
numberOfLines: 1,
ellipsizeMode: "tail",
},
}
);
You will need to do a few things in order to propagate the theme
prop into all of your styled components:
- Define your theme object and the type for it
- Augment the
Theme
type - Wrap your app in
ThemeProvider
First, define your theme:
// mytheme.ts
export const theme = {
primary: "blue",
background: "white",
...
} as const;
export type MyAppTheme = typeof theme;
TODO: add example on how to use multiple themes
Now you need to augment the default Theme
type with your own type. In order to do that, create a definitions file at the root of your source tree (e.g. global.d.ts
) and add the following to it:
import { MyAppTheme } from "./mytheme.ts";
declare module "styled-rn" {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface Theme extends MyAppTheme {}
}
And finally, the wrapping, as usual:
// App.tsx
import { ThemeProvider } from "styled-rn";
import { theme } from "./mytheme.ts";
export default function App() {
return (
<ThemeProvider theme={theme}>
{/* your app components */}
</ThemeProvider>;
)
}
And that's it! You can now access your theme in any styled component:
export const Button = styled.TouchableOpacity(({ theme }) => ({
backgroundColor: theme.background,
}));
If you want to use custom props in your styled component, make sure that your custom props interface extends StyledProps
. E.g.
// Important: π
interface ButtonProps extends StyledProps {
disabled?: boolean;
}
export const Button = styled.TouchableOpacity(({ disabled, theme }: ButtonProps) => ({
opacity: disabled ? 0.3 : 1,
backgroundColor: theme.background,
}));
// Using conditional styles with custom props
interface SmartComponentProps extends StyledProps {
active?: boolean;
}
export const SmartComponent = styled.TouchableOpacity(({ active, theme }: SmartComponentProps) => [
{
fontSize: 16,
},
active && {
fontWeight: theme.activeFontWeight,
color: theme.activeColor,
},
]);
You can also use theme
in your components by calling the useTheme()
hook or by wrapping your component with withTheme()
HOC.
import { useTheme } from "styled-rn";
export const MyComponent = () => {
const theme = useTheme();
};
There is also a special ctx
prop which you access easily from your styled component. It contains insets
and window
objects, which are the values returned by useSafeAreaInsets() and useWindowDimensions() respectively.
For example:
const TopBackButtonContainer = styled.TouchableOpacity(
({ theme, ctx }) =>
({
color: theme.primary,
position: "absolute",
top: ctx.insets.top || theme.spacing[1],
left: ctx.insets.left || theme.spacing[2],
zIndex: 10,
})
);
- When component returns the style from inline function sometimes the style object has to be type casted to ViewStyle, TextStyle, etc... Otherwise, you'll get a weird TS error. It looks like a TS bug. If you don't want to cast your styles, make sure that you pass props to the function and USE THE PROPS in your styles.
Issues and Pull Requests are always welcome.