Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork10
Easy theming and composition for CSS Modules.
License
FriendsOfReactJS/react-css-themr
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Easy theming and composition for CSS Modules.
$ npm install --save @friendsofreactjs/react-css-themrNote: Feedback and contributions on the docs are highly appreciated.
When you useCSS Modules to style your components, a classnames object is usually imported from the same component. Since css classes are scoped by default, there is no easy way to make your component customizable for the outside world.
Taking ideas fromfuture-react-ui andreact-themeable, a component should be shippedwithout styles. This means we can consider the styles as aninjectable dependency. In CSS Modules you can consider the imported classnames object as atheme for a component. Therefore, every styled component should define aclassname API to be used in the rendering function.
The most immediate way of providing a classname object is viaprops. In case you want to import a component with a theme already injected, you have to write a higher order component that does the job. This is ok for your own components, but for ui-kits likeReact Toolbox orBelle, you'd have to write a wrapper for every single component you want to use. In this fancy, you can understand the theme as aset of related classname objects for different components. It makes sense to group them together in a single object and move it through the component tree using a context. This way, you can provide a theme either viacontext,hoc orprops.
The approach of @friendsofreactjs/react-css-themr consists of aprovider and adecorator. The provider sets a context theme. The decorator adds to your components the logic to figure out which theme should be used or how should it be composed, depending on configuration, context and props.
There are three possible sources for your component. Sorted by priority:context,configuration andprops. Any of them can be missing. In case multiple themes are present, you may want to compose the final classnames object in three different ways:
- Override: the theme object with the highest priority is the one used.
- Softly merging: theme objects are merged but if a key is present in more than one object, the final value corresponds to the theme with highest priority.
- Deeply merging: theme objects are merged and if a key is present in more than one object, the values for each objects are concatenated.
You can choose whatever you want. We consider the last one as the most flexible so it's selectedby default.
Say you have aButton component you want to make themeable. You should pass a unique name identifier that will be used to retrieve its theme from context in case it is present.
// Button.jsimportReact,{Component}from'react';import{themr}from'@friendsofreactjs/react-css-themr';@themr('MyThemedButton')classButtonextendsComponent{render(){const{ theme, icon, children}=this.props;return(<buttonclassName={theme.button}>{icon ?<iclassName={theme.icon}>{icon}</i> :null}<spanclassName={theme.content}>{children}</span></button>)}}exportdefaultButton;
The component is defining an API for theming that consists of three classnames: button, icon and content. Now, a component can use a button with a success theme like:
importButtonfrom'./Button';importsuccessThemefrom'./SuccessButton.css';exportdefault(props)=>(<div{...props}><p>Do you like it?</p><Buttontheme={successTheme}>Yeah!</Button></div>);
If you use a component with a base theme, you may want to import the component with the theme already injected. Then you can compose its style via props with another theme object. In this case the base css willalways be bundled:
// SuccessButton.jsimportReact,{Component}from'react';import{themr}from'@friendsofreactjs/react-css-themr';importsuccessThemefrom'./SuccessButton.css';@themr('MySuccessButton',successTheme)classButtonextendsComponent{render(){const{ theme, icon, children}=this.props;return(<buttonclassName={theme.button}>{icon ?<iclassName={theme.icon}>{icon}</i> :null}<spanclassName={theme.content}>{children}</span></button>)}}exportdefaultButton;
Imagine you want to make the success button uppercase for a specific case. You can include the classname mixed with other classnames:
importReactfrom'react';importSuccessButtonfrom'SuccessButon';importstylefrom'./Section.css';exportdefault()=>(<sectionclassName={style.section}><SuccessButtontheme={style}>Yai!</SuccessButton></section>);
And beingSection.css something like:
.section {border:1pxsolidred; }.button {text-transform:uppercase; }
The final classnames object for theButton component would include class values fromSuccessButton.css andSection.css so it would be uppercase!
Although context theming is not limited to ui-kits, it's very useful to avoid declaring hoc for every component. For example, inreact-toolbox, you can define a context theme like:
importReactfrom'react';import{render}from'react-dom';import{ThemeProvider}from'@friendsofreactjs/react-css-themr';importAppfrom'./app'constcontextTheme={RTButton:require('react-toolbox/lib/button/style.scss'),RTDialog:require('react-toolbox/lib/dialog/style.scss')};constcontent=(<ThemeProvidertheme={contextTheme}><App/></ThemeProvider>);render(content,document.getElementById('app'));
The main idea is to inject classnames objects for each component via context. This way you can have the whole theme in a single place and forget about including styles in every require. AnyButton orDialog component will use the styles provided in the context.
Makes available atheme context to use in styled components. The shape of the theme object consists of an object whose keys are identifiers for styled components provided with thethemr function with each theme as the corresponding value. Useful for ui-kits.
Returns afunction to wrap a component and make it themeable.
The returned component accepts atheme,composeTheme,innerRef andmapThemrProps props apart from the props of the original component. The former two are used to provide atheme to the component and to configure the style composition, which can be configured via options too.innerRef is used to pass a ref callback to the decorated component andmapThemrProps is a function that can be used to map properties to the decorated component. The function arguments are:
Identifier(String) used to provide a unique identifier to the component that will be used to get a theme from context.[defaultTheme](Object) is classname object resolved from CSS modules. It will be used as the default theme to calculate a new theme that will be passed to the component.[options](Object) If specified it allows to customize the behavior:- [
composeTheme = 'deeply'](String) allows to customize the way themes are merged or to disable merging completely. The accepted values aredeeplyto deeply merge themes,softlyto softly merge themes andfalseto disable theme merging. - [
mapThemrProps = (props, theme) => ({ ref, theme })](Function) allows to customize how properties are passed down to the decorated component. By default, themr extracts all own properties passing down justinnerRefasrefand the generated theme astheme. If you are decorating a component that needs to map the reference or any other custom property, this function is called withall properties given to the component plus the generatedthemein the second parameter. It should return the properties you want to pass.
- [
We'd love you to contribute to react-css-themr. First, please read ourContribution Guide andCode of Conduct.
We try to make it as easy as possible.We are using semantic-release to have more time to concentrate on important stuffinstead of struggling in the dependency or release hell.
Therefore the first rule is to follow theeslint commit message guideline.When you always commit viayarn commit this is really easy. Commitizen will guide you.
All PRs will be merged into the develop branch. When we merge the develop into the mastertravis and semantic release will build a new release.
So no one can directly push into master!
We have some yarn scripts that should make live easier. The deployment scripts are just forsemantic-release and travis, but the following will help you.
| Command | Description |
|---|---|
yarn build | Runs the development build. |
yarn lint | Executes linter, we use prettier with eslint. |
yarn test | Executes the jest test on all source files. |
yarn test:watch | Perfect while writing tests is the watcher for test. |
yarn commit | Executes commitizen to guide you for the correct commit message. |
The project is originally authored byJavi Velasco as an effort of providing a better customization experience forReact Toolbox. Any comments, improvements or feedback is highly appreciated.
We thank Javi Velasco for all his efforts and for creating such a great package. The packagejavivelasco/react-css-themr should not be unmaintained - so the friends of react will continue.
Thanks toNik Graf andMark Dalgleish for their thoughts about theming and customization for React components.
This project is licensed under the terms of theMIT license.
About
Easy theming and composition for CSS Modules.
Topics
Resources
License
Code of conduct
Contributing
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Sponsor this project
Uh oh!
There was an error while loading.Please reload this page.
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors6
Uh oh!
There was an error while loading.Please reload this page.