You need to create one main file which will export all the parts of the package like StyleSheet, ThemeProvider, useTheme hook etc.
Here is a full example same for both Javascript and TypeScript projects.
STEP 1: style.tsx
Define configurations for your theme, for more verbose example see this file.
import Sugar from "react-native-sugar-style";
const commonTheme = {
fontSize: {
s: 12,
m: 16,
},
borderRadius: {
half: 12,
full: 20,
},
// add any custom value here
};
const dark = {
...commonTheme,
name: "dark",
background: "black",
text: "white",
buttonPrimary: "green",
surface: "gray",
};
const light = {
...commonTheme,
name: "light",
background: "white",
text: "black",
buttonPrimary: "red",
surface: "gray",
};
export const { StyleSheet, ThemeProvider, useTheme, withTheme } = Sugar(light);
export default StyleSheet;
the
name
key in theme object can be used to distinguish between themes while swapping
STEP 2: App.tsx
Wrap with ThemeProvider
import React from "react";
import { ThemeProvider } from "./style";
import Navigation from "./navigation";
const App = () => (
<ThemeProvider>
<Navigation />
</ThemeProvider>
);
STEP 3: component.tsx
Use StyleSheet as you do normally do in components
import React from "react";
import { View, Text } from "react-native";
import { StyleSheet, useTheme } from "./style";
const Component = () => {
useTheme();
return (
<View style={styles.container}>
<Text style={styles.text}>Hello World</Text>
</View>
);
};
const styles = StyleSheet.create((theme, constants) => ({
container: {
height: constants.height,
width: constants.width,
backgroundColor: theme.background,
flexDirection: ["column", "row", "row-reverse"], // column in mobile, row in tablet, row-reverse in desktop
},
text: {
fontSize: theme.fontSize.m,
color: theme.text,
},
}));
NOTE: if you add
useTheme()
in the navigation screen (parent component), then you can avoid using it in child components*
STEP 4: anotherComponent.tsx
To change the theme you can call build method and it will swap the theme
import React from "react";
import { View, Button } from "react-native";
import { StyleSheet, light, dark } from "./style";
const Component = () => {
const onLight = () => StyleSheet.build(light);
const onDark = () => StyleSheet.build(dark);
return (
<View>
<Button onPress={onLight} title="light theme" />
<Button onPress={onDark} title="dark theme" />
</View>
);
};
These are some device specific constants, that are dynamic and get updated when the platform or device dimensions change.
These can be used as a second parameter to the StyleSheet.create
function:
const styles = StyleSheet.create((theme, constants) => ({
container: {
height: constants.height,
width: constants.width,
marginTop: constants.statusBarHeight,
backgroundColor: constants.platform.ios ? "yellow" : "red",
},
}));
All the available value in constants are
Name | Type | Description |
---|---|---|
height | number | const {height} = Dimensions.get('window'); |
width | number | const {width} = Dimensions.get('window'); |
screenHeight | number | const {height} = Dimensions.get('screen'); |
screenWidth | number | const {width} = Dimensions.get('screen'); |
statusBarHeight | number | StatusBar.currentHeight |
navBarHeight | number | Height of the bottom navigation bar (android only) |
isNavBarVisible | boolean | bottom navigation is visible or not (android only) |
visibleHeight | number | the visible height of screen excluding the bottom navigation and status bar |
platform: {android, ios, windows, web, isPad, isTv, isIPhoneX} | boolean | Current active device platform |
-
StyleSheet.theme
Access the currently active theme
-
StyleSheet.constants
Access the constants
-
StyleSheet.create
Create a stylesheet object it can take a plain object or a function as parameter. If a plain object is passed that component is not re-rendered on theme change
// static const style1 = StyleSheet.create({ container: { flex: 1, }, }); // dynamic const style1 = StyleSheet.create((theme) => ({ container: { flex: 1, backgroundColor: theme.background, }, }));
-
StyleSheet.build
Build the stylesheet with a new theme, this will trigger re-render of all the components where StyleSheet.create is a function
StyleSheet.build(purpleTheme);
-
StyleSheet.configure
Configure the constants available throughout the app, you can change the global available height, width etc. This will also trigger re-render of all the components.
StyleSheet.configure({ height: 400, width: 200, // any other constant value });
-
StyleSheet.subscribe
Subscribe to theme changes it accepts event name (
build
) and a callback functionStyleSheet.subscribe("build", () => { console.log("build happened"); });
-
StyleSheet.unsubscribe
Unsubscribe to theme changes it accepts event name (
build
) and a callback function
-
StyleSheet.theme.name
It is a simple hack to get the currently active theme, you just need to have
name
key in theme configuration as stated above, and you can get the currently active theme inside or outside your components.StyleSheet.theme.name; // or const [theme, constants] = useTheme();
There are many awesome solutions for styling in React Native. Through this package i wanted to explore and experiment a way to achieve a development experience which is very similar to the existing react native pattern, with the ability to get dynamic theme value and can be used in functional and class based components.
Special thanks to the author of the amazing open source library React Native Extended Stylesheet
- May introduce performance issues (not tested)