This is basically styled-components with a much better support for React-Native, and some awesome additional features. You can check the docs of styled-components for more details about the basic API. I'll focus here on the differences.
Current version: 1.10 See the Changelog
The goal here is to be able to write a common code for React-Native-Web and React-Native without having to worry about the limitations of React-Native. React-Native supports only a subset of CSS but with rn-css
you will be able to style your components as if you were using React. See:
const MyComponent = styled.View`
width: 2em;
height: 2em;
border-radius: 50%;
&:hover {
background: red;
}
&:active {
background: blue;
}
@media (min-width: 600px) {
border: 1px solid rgb(128, 128, 128);
}
`
Here is a list of the units supported by rn-css
. You can use them as you wish within your components:
- px
- pc
- em
- rem
- cm
- mm
- vh
- vw
- vmin
- vmax
There is only partial support for %
units as I didn't find a way to retrieve the parent's size without a reference to the parent... I'll detail here what you can do and what you probably can't.
%
without calc
, min
, max
: You should be able to use %
for the following CSS properties, as long as you don't use calc
, min
or max
:
- width
- height
- min-width
- min-height
- max-width
- max-height
- top
- bottom
- left
- right
- flex-basis
- border
%
with calc
, min
, max
: You can try using %
inside calc
, min
or max
with the following CSS props, it should work as expected:
- font-size
- margin-left
- margin-right
- margin-top
- margin-bottom
Here is a bunch of cool feature that you can use with this lib!
Just like styled-components
, you can access your props with a function:
const View = styled.View`
color: ${props => props.color || 'black'}
`
Here is for usage with typescript:
const View = styled.View<{ color: string }>`
color: ${props => props.color || 'black'}
`
Here is an example returning directly a Style object:
const View = styled.View`
color: black;
${props => ({ justifyContent: props.center })}
`
You can inject props with attrs: styled(MyComp).attrs({ ...props })
or styled(MyComp).attrs(props => ({ ...newProps }))
const View = styled.View.attrs({ color: 'blue' })`
width: calc(200px - 10em);
background: ${props => props.color};
`
Here is the typescript version:
const View = styled.View.attrs<{ color: string }>({ color: 'blue' })`
width: calc(200px - 10em);
background: ${props => props.color};
`
Here is the version with a function:
const View = styled.View.attrs(props => ({ fontSize: props.fontSize * 2 }))`
fontSize: ${props => props.fontSize};
background: ${props => props.color};
`
This is very handy! You can inject any css string with the rnCSS props:
const View = styled.View``
return <View rnCSS="width=2em;height=3em;"/>
Do not forget to close the string with a semicolon
You can extend components this way:
const MyComponent = styled.View`
background-color: red;
`
const Extended = styled(MyComponent)`
background-color: blue;
`
** IMPORTANT:** To extend custom components, you need to propagate the style prop:
const MyComponent = ({ style, ...props }) => {
return <View style={style}>
...
</View>
}
const Extended = styled(MyComponent)`
background-color: blue;
`
If, somewhere within your app, you need to access the current font size value in px to be able to manually convert em into px, you can use the FontSizeContext
. This can be helpful if you want to change some behaviour within your app depending on the font size.
import { FontSizeContext } from 'rn-css'
...
const [width, setWidth] = React.useState(0)
const em = React.useContext(FontSizeContext)
if(width < 70 * em) { /* Do something when width is lesser than 70em */ }
return <View onLayout={event => setWidth(event.nativeEvent.layout.width)}>...</View>
Default value for rem
units is 16. If you want to declare another value, you can use RemContext
:
import { RemContext } from 'rn-css'
...
return <RemContext.Provider value={10}>{children}</RemContext.Provider>
If, for some reason, you just want to convert a css string to a ReactNative Style object, you can use this feature:
import { cssToRNStyle } from 'rn-css'
...
const style = cssToRNStyle('width: 2em; border-width: 12px; background: blue;')
const { width = 32, borderLeftWidth = 12, backgroundColor = 'blue' } = style
The second parameter lets you provide:
- em : (Default: 16) the current value of em unit for font size. You can retrieve the current context value with the
FontSizeContext
. - width (Default: 100) the reference width that will be used to calculate percentages for the following properties:
marginLeft
,marginRight
,translateX
andborderRadius
- height (Default: 100) the reference width that will be used to calculate percentages for the following properties:
marginTop
,marginBottom
,translateY
andborderRadius
import { cssToRNStyle, FontSizeContext } from 'rn-css'
...
const style = cssToRNStyle('width: 2em; margin: 10%;', { em: React.useContext(FontSizeContext), width: 100, height: 100 })
const { width: 32, marginTop: 10, marginLeft: 10, marginRight: 10, marginBottom: 10 } = style
If you want to use this feature in a non react project, you can use import { cssToRNStyle } from 'rn-css/cssToRN'
.
We support some cool CSS feature that React-Native doesn't normally handle
You can add hover with &:hover { <instructions> }
const Hoverable = styled.View`
background: red;
&:hover {
background: blue;
}
`
You can add styles on the element the user is interacting with by using &:active { <instructions> }
. A button is considered active
from the moment the touch start until the touch ends
const Activable = styled.View`
background: red;
&:active {
background: blue;
}
`
You can add styles on the element if it owns the focus with &:focus { <instructions> }
.
const Activable = styled.View`
background: red;
&:focus {
background: blue;
}
`
You can add media queries with @media <constraints> { <instructions> }
const ResponsiveView = styled.View`
background: red;
@media (min-width: 600px) {
background: blue;
}
`
You can use all supported units in the media query.
If rn-css encounters text-overflow: ellipsis;
, it will be transform into numberOfLines: 1
, which should give the desired effect.
const Text = styled.Text`
text-overflow: ellipsis;
`
rn-css will try to handle z-index as best as possible so that components from different trees can be correctly compared and positioned. In iOS, when a z-index is set, each parent will automatically receive this z-index, unless another value is set. This generally ensure that the behaviour matches the one from web. If you encounter an issue, please report. We might probably fix this.
const View = styled.View`
z-index: 10;
`
You can write things like calc(2em - 1px)
. Keep in mind that the support for % is limited right now.
const View = styled.View`
width: calc(200px - 10em);
`
You can write things like min(2em, 10px)
. Keep in mind that the support for % is limited right now.
const View = styled.View`
width: min(2em, 10px);
`
You can write things like max(2em, 10px)
. Keep in mind that the support for % is limited right now.
const View = styled.View`
width: max(2em, 10px);
`
If you want to share some data with all of your components, like a theme, you can use the SharedValues
context. Use it this way:
return <SharedValue.Provider value={{ green: '#00FF00', red: '#FF0000' }}>{children}</SharedValue.Provider>
const View = styled.View`
border-color: ${props => props.shared.green};
`
For Typescript, shared
will always be typed with unknown
. You need to manually declare the type of your shared object. Read the Theming section to learn more about workarounds.
// Create your theme
const theme = { green: '#00FF00', red: '#FF0000' } as const
type Theme = typeof theme
// Somewhere in your React tree:
// <SharedValue.Provider value={theme}>{children}</SharedValue.Provider>
// Use your shared theme
const View = styled.View`
border-color: ${props => (props.shared as Theme).green;
`
To match the API of styled-components, we offer the same abilities for theming See the documentation.
This relies on the SharedValue context. This means that you cannot use the Shared Value system and this theming système. Pick the one that best suits your needs.
When you use the theme prop in your components, it is initially typed as unknown
. But you can make it follow your custom type by extending the type declaration of rn-css. You will need to create a file rncss.d.ts
in the src
of your project root and add the following lines:
import 'rn-css';
declare module 'rn-css' {
type MyTheme = {
// Describe your theme here.
// Alternatively, you can use: `type MyTheme = typeof theme` if you have a fixed `theme` object.
}
export interface DefaultTheme extends MyTheme {}
}
linear-gradient, background-repeat, transitions, animations