Theming
Primer Brand defines various global styling defaults using CSS variables, while also allowing app-level customization through its ThemeProvider.
CSS variables are available for most styling dimensions such as typography, color and sizing. They are defined in the primary stylesheet: main.css.
ThemeProvider extends theming capabilities at runtime by enabling real-time color mode switching among other things.
Using the CSS stylesheet and ThemeProvider in tandem is crucial to make theming work correctly.
The ThemeProvider should wrap your React application root to enable theming correctly. It can also be nested to apply isolated behavior to children.
import {ThemeProvider} from '@primer/react-brand'
function App() {
return (
<ThemeProvider>
<div>...</div>
</ThemeProvider>
)
}
The stylesheet contains all of the required rules for design tokens and components. It also includes a CSS reset, so we recommend loading this as early as possible in your HTML <head> to minimize undesirable rendering behavior.
import '@primer/react-brand/lib/css/main.css'
Primer Brand supports the following color modes through a dedicated prop by applying HTML data-* attributes:
| Theme | colorMode prop value | Data attribute applied |
|---|
| Light | light | data-color-mode="light" |
| Dark | dark | data-color-mode="dark" |
The ThemeProvider applies the data attributes and handles state-changes internally.
ThemeProvider will apply light mode by default if the colorMode is not specified. This is recommended for top-level placement.
The following example demonstrates how light mode will enable by default, and can also be changed to dark declaratively:
const Example = () => {
const [colorMode, setColorMode] = React.useState()
const handleChange = (event) => {
event.preventDefault()
setColorMode('dark')
}
return (
<ThemeProvider
colorMode={colorMode}
style={{backgroundColor: 'var(--brand-color-canvas-default)'}}
>
<River>
<River.Visual>
<img
src="https://via.placeholder.com/600x400/f5f5f5/f5f5f5.png"
alt="placeholder, blank area with an off-white background color"
/>
</River.Visual>
<River.Content>
<Heading>Heading</Heading>
<Text>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In sapien
sit ullamcorper id. Aliquam luctus sed turpis felis nam pulvinar
risus elementum.
</Text>
<Link href="#" onClick={handleChange}>
{colorMode === 'dark'
? "I'm in dark mode now"
: 'Switch to dark mode'}
</Link>
</River.Content>
</River>
</ThemeProvider>
)
}
render(Example)
For tighter control over appearance - such as forcing areas of a layout to appear in dark mode - we recommend nesting ThemeProvider and explicitly applying a color mode.
<>
<ThemeProvider
colorMode="dark"
style={{
backgroundColor: 'var(--brand-color-canvas-default)',
}}
>
<River align="center">
<River.Visual>
<img
src="https://via.placeholder.com/600x400/f5f5f5/f5f5f5.png"
alt="placeholder, blank area with an off-white background color"
/>
</River.Visual>
<River.Content>
<Heading>Heading</Heading>
<Text>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In sapien sit
ullamcorper id. Aliquam luctus sed turpis felis nam pulvinar risus
elementum.
</Text>
<Link href="#">Call to action</Link>
</River.Content>
</River>
</ThemeProvider>
<ThemeProvider
colorMode="light"
style={{
backgroundColor: 'var(--brand-color-canvas-default)',
}}
>
<Container>
<River align="right">
<River.Visual>
<img
src="https://via.placeholder.com/600x400/f5f5f5/f5f5f5.png"
alt="placeholder, blank area with an off-white background color"
/>
</River.Visual>
<River.Content>
<Heading>Heading</Heading>
<Text>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In sapien
sit ullamcorper id. Aliquam luctus sed turpis felis nam pulvinar
risus elementum.
</Text>
<Link href="#">Call to action</Link>
</River.Content>
</River>
</Container>
</ThemeProvider>
</>