ThemeProvider
The previous solution works great for only one component, but imagine having to do this for every component you want custom styles for. That could get a bit tedious to manage. Thankfully, there's a better way to do this. React Native Elements ships with a 3 utilities for large-scale theming.
Firstly you'll want to set up your ThemeProvider.
import { ThemeProvider, Button, createTheme } from '@rneui/themed';
const theme = createTheme({
components: {
Button: {
raised: true,
},
},
});
// Your App
const App = () => {
return (
<ThemeProvider theme={theme}>
<Button>My Button</Button>
</ThemeProvider>
);
};
If you do not specify theme in ThemeProvider, it would use defaultTheme
The example above achieves the same goals as the first example — apply the same
styles to multiple instances of Button in the app. However this example
applies the raised prop to every instance of Button inside the component
tree under ThemeProvider. Both of these buttons will have the raised prop
set to true.
This is extremely convenient and is made possible through React's Context API.
To theme subcomponents such as ListItem.Title, in your theme remove the dot and list them as "ListItemTitle"
use-theme hook
Hook returns theme, updateTheme & replaceTheme from ThemeProvider context or default theme if you did not wrap application with ThemeProvider.
import { useTheme } from '@rneui/themed';
function Demo() {
const { theme, updateTheme } = useTheme();
return (
<View style={{ background: theme.colors.primary }}>
<Button onPress={() => updateTheme({ colors: { primary: 'red' } })} />
</View>
);
}
The updateTheme function merges the theme passed in with the current theme.
updateTheme({
lightColors: {
primary: 'purple',
},
});
The replaceTheme function merges the theme passed in with the default theme.
use-theme-mode hook
You can get current theme mode (light or dark) and update it using setMode function from useThemeMode hook.
import { useThemeMode } from '@rneui/themed';
function Demo() {
const { mode, setMode } = useThemeMode();
return <Button onPress={() => setMode('dark')} title={mode} />;
}
make-styles
If you want to keep your styles outside the component use makeStyles() (hook generator) to reference the theme and component props (optional param).
import React from 'react';
import { Text } from 'react-native';
import { makeStyles } from '@rneui/themed';
type Props = {
fullWidth?: boolean;
};
const MyComponent = (props: Props) => {
const styles = useStyles(props);
return (
<View style={styles.container}>
<Text style={{ color: theme.colors.primary }}>Yo!</Text>
</View>
);
};
const useStyles = makeStyles((theme, props: Props) => ({
container: {
background: theme.colors.white,
width: props.fullWidth ? '100%' : 'auto',
},
text: {
color: theme.colors.primary,
},
}));
Don't want to wrap your components with withTheme? You can use the ThemeConsumer component
which uses render props!
import React from 'react';
import { Text } from 'react-native';
import { ThemeConsumer } from '@rneui/themed';
const MyComponent = () => (
<ThemeConsumer>
{({ theme }) => (
<Text style={{ color: theme.colors.primary }}>Yo!</Text>;
)}
</ThemeConsumer>
)
Dark Mode
import { useColorScheme } from 'react-native-appearance';
const theme = createTheme({
lightColors: {
primary: '#899656',
},
darkColors: {
primary: '#344512',
},
mode: 'light',
});
const ColorScheme = ({ children }) => {
const colorMode = useColorScheme();
const { theme } = useTheme();
const { setMode } = useThemeMode();
React.useEffect(() => {
setMode(colorMode);
}, [colorMode]);
return (
<View style={{ backgroundColor: theme.colors.background }}>{children}</View>
);
};
const App = () => {
return (
<ThemeProvider theme={theme}>
<ColorScheme>{/* */}</ColorScheme>
</ThemeProvider>
);
};