Skip to content

diffcunha/react-css-themes

Repository files navigation

npm versionCode ClimateTest Coverage

react-css-themes

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

Table of contents

Installation

npm i --save react-css-themes

Usage [API]

withThemes(themeTypes, [themes], [defaultTheme])

Arguments:
  • themeTypes(Object) - Theme types definition
  • themes(Object) - The available themes
  • defaultTheme(Object) - The default theme
Returns:

Returns a decorator `function to make Component themeable.

Example:
importReactfrom'react'importwithThemes,{ThemeTypes}from'react-css-themes'importlightfrom'./light.css'importdarkfrom'./dark.css'constThemableComponent=({ theme })=>(<divclassName={theme.container}><divclassName={theme.heading}>Heading</div></div>)ThemableComponent.themeTypes={container: ThemeTypes.className,heading: ThemeTypes.className}exportdefaultwithThemes({ light, dark },light)(ThemableComponent)

ThemeTypes

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 className
  • ThemeTypes.themeOf(ThemableComponent): Define a property as a theme of another themeable compoenent
Example:
importReactfrom'react';import{ThemeTypes}from'react-css-themes'functionMyComponent({ theme }){// ... do things with the props}MyComponent.themeTypes={themeProp: ThemeTypes.className,childComponent: ThemeTypes.themeOf(ThemableComponent),}

Component.themes

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.

add(fragment)

Arguments:
  • fragment(Object) - ClassNames to add to the theme
Returns:

A new theme derived from the original theme plus the fragment

Example:
letThemableComponent=({ theme })=>(<divclassName={theme.container}/>)ThemableComponent=withThemes({light: {container: '.container'}},light)(ThemableComponent)/* HTML output */renderToStaticMarkup(<ThemableComponent/>)// <div class=".container"></div>// Derived themeconsttheme=ThemableComponent.themes.light.add({container: '.foobar'})renderToStaticMarkup(<ThemableComponenttheme={theme}/>)// <div class=".container .foobar"></div>

Examples

Basic theming

/* ThemableComponent.js */importReactfrom'react'importwithThemes,{ThemeTypes}from'react-css-themes'importlightfrom'./light.css'importdarkfrom'./dark.css'constThemableComponent=({ theme })=>(<divclassName={theme.container}><divclassName={theme.heading}>Heading</div></div>)ThemableComponent.themeTypes={container: ThemeTypes.className,heading: ThemeTypes.className}exportdefaultwithThemes({ light, dark },light)(ThemableComponent)
/* light.css */ .container{background-color: white} .heading{color: black}
/* dark.css */ .container{background-color: black} .heading{color: white}
/* View.js */importReactfrom'react'importThemableComponentfrom'./ThemableComponent'constView=()=>(<div><ThemableComponenttheme={ThemableComponent.themes.light}/><ThemableComponenttheme={ThemableComponent.themes.dark}/><ThemableComponent/> /* Default theme (light) will be used */ </div>)exportdefaultView

Composing themable components

/* AnotherThemableComponent.js */importReactfrom'react'importwithThemes,{ThemeTypes}from'react-css-themes'importthemeAfrom'./themeA.css'importthemeBfrom'./themeB.css'constTHEMES={themeA: { ...themeA,child1: ThemableComponent.themes.light,child2: ThemableComponent.themes.dark},themeB: { ...themeB,child1: ThemableComponent.themes.dark,child2: ThemableComponent.themes.light}}constAnotherThemableComponent=({ theme })=>(<divclassName={theme.container}><ThemableComponenttheme={theme.child1}/><ThemableComponenttheme={theme.child2}/></div>)AnotherThemableComponent.themeTypes={container: ThemeTypes.className,child1: ThemeTypes.themeOf(ThemableComponent),child2: ThemeTypes.themeOf(ThemableComponent)}exportdefaultwithThemes(THEMES,THEMES.themeA)(AnotherThemableComponent)

Adding classNames to a deeply nested themeable child

/* AnotherThemableComponent.js */importReactfrom'react'importwithThemes,{ThemeTypes}from'react-css-themes'importthemeAfrom'./themeA.css'constTHEMES={themeA: { ...themeA,child: ThemableComponent.themes.light.add({container: themeA.childContainer,heading: themeA.childHeading})}}constAnotherThemableComponent=({ theme })=>(<divclassName={theme.container}><ThemableComponenttheme={theme.child}/></div>)

About

The project is authored by Diogo Cunha (@diffcunha) and Daniel Hayes (@daniel-hayes).

Comments, improvements or feedback are highly appreciated.

License

This project is licensed under the terms of the ISC license.

About

Theme provider for React components using CSS modules

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published