⚠️ NOTE: This library is still under development and not yet published on npm.
npm install stitches-native
or if you use yarn
:
yarn add stitches-native
For the most part Stitches Native behaves exactly as Stitches so you should follow the Stitches documentation to learn the basic principles and how to setup everything.
Due to the inherit differences between the Web and native platforms (iOS + Android) the implementation of Stitches Native differs slightly from the original Web version of Stitches.
First of all, CSS in React Native doesn't have CSS Variables, cascade, inheritance, keyframes, pseudo elements/classes, or global styles which means that some features that are available in Stitches are not possible to implement in Stitches Native.
Below you can see a list of all supported and unsupported features of Stitches Native.
Feature | Supported |
---|---|
styled |
✅ |
createCss |
✅ |
defaultThemeMap |
✅ |
css |
✅ (Simplified version) |
theme |
✅ (Based on React Context) |
global |
❌ (No global styles in RN) |
keyframes |
❌ (No CSS keyframes in RN) |
getCssString |
❌ (SSR not applicable to RN) |
Nesting | ❌ (No CSS cascade in RN) |
Selectors | ❌ (No CSS selectors in RN) |
Locally scoped tokens | ❌ (No CSS variables in RN) |
Pseudo elements | ❌ (No pseudo elements/classes in RN) |
The createCss
function doesn't need prefix
or insertionMethod
since they are not used in the native implementation.
import { createCss } from 'stitches-native';
createCss({
theme: object,
media: object,
utils: object,
themeMap: object,
});
The return value of createCss
doesn't include global
, keyframes
, or getCssString
since they are not available in native platforms. React Native doesn't have any CSS keyframes based animations and all animations should be handled by the Animated API or with libraries such as react-native-reanimated.
The return value of createCss
consist of the following:
const { styled, css, theme, config } = createCss({
/*...*/
});
Unlike on the Web there is no concept of className
in React Native so the css
function is basically an identity function providing only TS types for the style object and returning exactly the same object back. The returned object can be spread to a styled component or into the css prop of a component.
const styles = css({
backgroundColor: '$background', // <- get autocomplete for theme values
});
const SomeComp = styled('View', {
// ...other styles...
...styles,
});
<AnotherComp css={styles} />;
Stitches Native handles theming differently than Stitches. Since there are no CSS Variables in React Native theming is handled via React Context in a similar way as other CSS-in-JS libraries such as styled-components handle theming.
const { theme, ThemeProvider } = createCss({
colors: {
background: '#fff',
text: '#000',
},
});
const darkTheme = theme({
colors: {
background: '#000',
text: '#fff',
},
});
export default function App() {
// In a real world scenario this value should probably live in React Context
const [darkMode, setDarkMode] = useState(false);
return (
<ThemeProvider theme={darkMode ? darkTheme : undefined}>
{/*...*/}
</ThemeProvider>
);
}
Responsive styles are not very common in React Native applications since you usually have a clearly constrained device environment where the app is used. However, some times you might need to tweak a style for very small or large phones or build an app that needs to adapt to tablet devices. For these use cases Stitches Native has support for two kinds of responsive styles:
- Device types based media flags
- Device dimensions based media queries
Simple boolean flags in the media
config can be used to distinguish between device types, eg. phone vs. tablet. You can utilize getDeviceType()
or isTablet()
from react-native-device-info to get the device type.
const isTablet = DeviceInfo.isTablet();
const { theme, ThemeProvider } = createCss({
media: {
phone: !isTablet,
tablet: isTablet,
},
});
Then you can apply different prop values for variants of a styled components based on the device type:
const ButtonText = styled('Text', {
// base styles
variants: {
color: {
primary: {
color: '$primary',
},
secondary: {
color: '$secondary',
},
},
},
});
<ButtonText color={{ '@phone': 'primary', '@tablet': 'secondary' }}>
Hello
</ButtonText>
It's also possible to have a more Web-like breakpoint system based on the dimensions of the device. The syntax for the queries follows the CSS range queries syntax which means that there is no need to use min-width
or max-width
.
Examples of supported range queries:
(width > 750px)
(width >= 750px)
(width < 1080px)
(width <= 1080px)
(750px > width >= 1080px)
⚠️ NOTE: Only width based media queries are currently supported.
const { theme, ThemeProvider } = createCss({
media: {
md: '(width >= 750px)',
lg: '(width >= 1080px)',
xl: '(width >= 1284px)',
xxl: '(width >= 1536px)',
},
});
⚠️ NOTE: The order of the media query keys matters and the responsive styles are applied in the order determined byObject.entries
method.
Using media queries works the same way as device type flags:
const ButtonText = styled('Text', {
// base styles
variants: {
color: {
primary: {
color: '$primary',
},
secondary: {
color: '$secondary',
},
},
},
});
<ButtonText
color={{
'@initial': 'primary',
'@md': 'secondary',
'@lg': 'tertiary',
}}
>
Hello
</ButtonText>