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>
);
};