Theme provider for React components using CSS modules.
Key Features
- Themable components expose API to allow external theming
- Easy to change themes of deeply nested themable components
npm i --save react-css-themes
themeTypes
(Object
) - Theme types definitionthemes
(Object
) - The available themesdefaultTheme
(Object
) - The default theme
Returns a decorator `function to make Component themeable.
import React from 'react'
import withThemes, { ThemeTypes } from 'react-css-themes'
import light from './light.css'
import dark from './dark.css'
const ThemableComponent = ({ theme }) => (
<div className={theme.container}>
<div className={theme.heading}>Heading</div>
</div>
)
ThemableComponent.themeTypes = {
container: ThemeTypes.className,
heading: ThemeTypes.className
}
export default withThemes({ light, dark }, light)(ThemableComponent)
ThemeTypes
are used to define theme's property types. It's simillar to React PropTypes
, there are 2 avaiable types:
ThemeTypes.className
: Defines a property as a classNameThemeTypes.themeOf(ThemableComponent)
: Define a property as a theme of another themeable compoenent
import React from 'react';
import { ThemeTypes } from 'react-css-themes'
function MyComponent ({ theme }) {
// ... do things with the props
}
MyComponent.themeTypes = {
themeProp: ThemeTypes.className,
childComponent: ThemeTypes.themeOf(ThemableComponent),
}
The compoenent will expose a themes
object property with the themes defined as keys. These themes are set by the compoenent but also expose an API to create derivated themes.
fragment
(Object
) - ClassNames to add to the theme
A new theme derived from the original theme plus the fragment
let ThemableComponent = ({ theme }) => (
<div className={theme.container} />
)
ThemableComponent = withThemes({
light: {
container: '.container'
}
}, light)(ThemableComponent)
/* HTML output */
renderToStaticMarkup(<ThemableComponent />)
// <div class=".container"></div>
// Derived theme
const theme = ThemableComponent.themes.light.add({
container: '.foobar'
})
renderToStaticMarkup(<ThemableComponent theme={theme} />)
// <div class=".container .foobar"></div>
/* ThemableComponent.js */
import React from 'react'
import withThemes, { ThemeTypes } from 'react-css-themes'
import light from './light.css'
import dark from './dark.css'
const ThemableComponent = ({ theme }) => (
<div className={theme.container}>
<div className={theme.heading}>Heading</div>
</div>
)
ThemableComponent.themeTypes = {
container: ThemeTypes.className,
heading: ThemeTypes.className
}
export default withThemes({ light, dark }, light)(ThemableComponent)
/* light.css */
.container {
background-color: white;
}
.heading {
color: black;
}
/* dark.css */
.container {
background-color: black;
}
.heading {
color: white;
}
/* View.js */
import React from 'react'
import ThemableComponent from './ThemableComponent'
const View = () => (
<div>
<ThemableComponent theme={ThemableComponent.themes.light} />
<ThemableComponent theme={ThemableComponent.themes.dark} />
<ThemableComponent /> /* Default theme (light) will be used */
</div>
)
export default View
/* AnotherThemableComponent.js */
import React from 'react'
import withThemes, { ThemeTypes } from 'react-css-themes'
import themeA from './themeA.css'
import themeB from './themeB.css'
const THEMES = {
themeA: {
...themeA,
child1: ThemableComponent.themes.light,
child2: ThemableComponent.themes.dark
},
themeB: {
...themeB,
child1: ThemableComponent.themes.dark,
child2: ThemableComponent.themes.light
}
}
const AnotherThemableComponent = ({ theme }) => (
<div className={theme.container}>
<ThemableComponent theme={theme.child1} />
<ThemableComponent theme={theme.child2} />
</div>
)
AnotherThemableComponent.themeTypes = {
container: ThemeTypes.className,
child1: ThemeTypes.themeOf(ThemableComponent),
child2: ThemeTypes.themeOf(ThemableComponent)
}
export default withThemes(THEMES, THEMES.themeA)(AnotherThemableComponent)
/* AnotherThemableComponent.js */
import React from 'react'
import withThemes, { ThemeTypes } from 'react-css-themes'
import themeA from './themeA.css'
const THEMES = {
themeA: {
...themeA,
child: ThemableComponent.themes.light.add({
container: themeA.childContainer,
heading: themeA.childHeading
})
}
}
const AnotherThemableComponent = ({ theme }) => (
<div className={theme.container}>
<ThemableComponent theme={theme.child} />
</div>
)
The project is authored by Diogo Cunha (@diffcunha) and Daniel Hayes (@daniel-hayes).
Comments, improvements or feedback are highly appreciated.
This project is licensed under the terms of the ISC license.