Theming
Applying a theme to the whole app
To support custom themes, paper exports a Provider
component. You need to wrap your root component with the provider to be able to support themes:
import * as React from 'react';
import { Provider as PaperProvider } from 'react-native-paper';
import App from './src/App';
export default function Main() {
return (
<PaperProvider>
<App />
</PaperProvider>
);
}
If no prop is specified, this will apply the default theme to the components. You can also provide a theme
prop with a theme object with same properties as the default theme:
import * as React from 'react';
import { DefaultTheme, Provider as PaperProvider } from 'react-native-paper';
import App from './src/App';
const theme = {
...DefaultTheme,
roundness: 2,
colors: {
...DefaultTheme.colors,
primary: '#3498db',
accent: '#f1c40f',
},
};
export default function Main() {
return (
<PaperProvider theme={theme}>
<App />
</PaperProvider>
);
}
You can change the theme prop dynamically and all the components will automatically update to reflect the new theme.
A theme usually contains the following properties:
dark
(boolean
): whether this is a dark theme or light theme.mode
('adaptive' | 'exact'
): color mode for dark theme (See Dark Theme).roundness
(number
): roundness of common elements, such as buttons.colors
(object
): various colors used throughout different elements.primary
- primary color for your app, usually your brand color.accent
- secondary color for your app which complements the primary color.background
- background color for pages, such as lists.surface
- background color for elements containing content, such as cards.text
- text color for content.disabled
- color for disabled elements.placeholder
- color for placeholder text, such as input placeholder.backdrop
- color for backdrops of various components such as modals.onSurface
- background color for snackbarsnotification
- background color for badges
fonts
(object
): various fonts used throughout different elements.regular
medium
light
thin
animation
(object
)scale
- scale for all animations
When creating a custom theme, you will need to provide all of these properties.
If you don't use a custom theme, Paper will automatically turn animations on/off, depending on device settings.
Otherwise, your custom theme will need to handle it manually, using React Native's AccessibilityInfo API.
Extending the theme
Keeping your own properties in the theme is fully supported by our library:
import * as React from 'react';
import { DefaultTheme, Provider as PaperProvider } from 'react-native-paper';
import App from './src/App';
const theme = {
...DefaultTheme,
// Specify custom property
myOwnProperty: true,
// Specify custom property in nested object
colors: {
myOwnColor: '#BADA55',
}
};
export default function Main() {
return (
<PaperProvider theme={theme}>
<App />
</PaperProvider>
);
}
TypeScript
By default it won't work well with TypeScript, but we can take advantage of global augmentations
and specify the new properties that we added to the theme:
import * as React from 'react';
import { DefaultTheme, Provider as PaperProvider } from 'react-native-paper';
import App from './src/App';
declare global {
namespace ReactNativePaper {
interface ThemeColors {
myOwnColor: string;
}
interface Theme {
myOwnProperty: boolean;
}
}
}
const theme = {
...DefaultTheme,
// Specify custom property
myOwnProperty: true,
// Specify custom property in nested object
colors: {
myOwnColor: '#BADA55',
}
};
export default function Main() {
return (
<PaperProvider theme={theme}>
<App />
</PaperProvider>
);
}
As you can see, custom properties e.g. myOwnColor
defined in nested object e.g. colors
needs to be declared in its own interface. You'll find more information in our example app where we have it implemented.
Applying a theme to a paper component
If you want to change the theme for a certain component from the library, you can directly pass the theme
prop to the component. The theme passed as the prop is merged with the theme from the Provider
:
import * as React from 'react';
import { Button } from 'react-native-paper';
export default function ButtonExample() {
return (
<Button raised theme={{ roundness: 3 }}>
Press me
</Button>
);
}
Using the theme in your own components
To access the theme in your own components, you can use the withTheme
HOC exported from the library. If you wrap your component with the HOC, you'll receive the theme as a prop:
import * as React from 'react';
import { withTheme } from 'react-native-paper';
function MyComponent(props) {
const { colors } = props.theme;
return <Text style={{ color: colors.primary }}>Yo!</Text>;
}
export default withTheme(MyComponent);
Components wrapped with withTheme
support the theme from the Provider
as well as from the theme
prop.
You can also use the useTheme
hook:
import * as React from 'react';
import { useTheme } from 'react-native-paper';
function MyComponent(props) {
const { colors } = useTheme();
return <Text style={{ color: colors.primary }}>Yo!</Text>;
}
Customizing all instances of a component
Sometimes you want to style a component in a different way everywhere but don't want to change the properties in the theme so that other components are not affected. For example, say you want to change the font for all your buttons, but don't want to change theme.fonts.medium
because it affects other components.
We don't have an API to do this, because you can already do it with components:
import * as React from 'react';
import { Button } from 'react-native-paper';
export default function FancyButton(props) {
return <Button theme={{ fonts: { medium: 'Open Sans' } }} {...props} />;
}
Now you can use your FancyButton
component everywhere instead of using Button
from Paper.
Dark Theme
Since 3.0 we adapt dark theme to follow Material design guidelines.
In contrast to light theme, dark theme by default uses surface
colour instead of primary
on large components like AppBar
or BottomNavigation
.
The dark theme adds a white overlay with opacity depending on elevation of surfaces. It uses it for the better accentuation of surface elevation. Using only shadow is highly imperceptible on dark surfaces.
We are aware that users often use dark theme in their own ways and may not want to use the default dark theme features from the guidelines.
That's why if you are using dark theme you can switch between two dark theme mode
s:
exact
where everything is like it was before.Appbar
andBottomNavigation
will still use primary colour by default.adaptive
where we follow Material design guidelines, the surface will use white overlay with opacity to show elevation,Appbar
andBottomNavigation
will use surface colour as a background.
If you don't use a custom theme, Paper will automatically change between the default theme and the default dark theme, depending on device settings.
Otherwise, your custom theme will need to handle it manually, using React Native's Appearance API.
Gotchas
The Provider
exposes the theme to the components via React's context API, which means that the component must be in the same tree as the Provider
. Some React Native components will render a different tree such as a Modal
, in which case the components inside the Modal
won't be able to access the theme. The work around is to get the theme using the withTheme
HOC and pass it down to the components as props, or expose it again with the exported ThemeProvider
component.
The Modal
component from the library already handles this edge case, so you won't need to do anything.