reshadow ⛱️
Markup and styles that feel right.
Please check the reshadow.dev website to get more information and examples.
reshadow provides the Shadow DOM developer experience, but for the Virtual DOM with the Component way.
import React from 'react';
import styled, {css} from 'reshadow';
// Write styles:
const styles = css`
button {
width: 200px;
}
content {
font-size: 14px;
}
`;
export const Button = ({children, ...props}) => {
// connect the styles to the markup:
return styled(styles)(
<button {...props}>
<content as="span">{children}</content>
</button>,
);
};
This project has
alpha
status, so the API and the implementation could be changed.
Features
- Get away from additional abstractions
- Write isolated semantic styles for the Virtual DOM in a native like way
- Match styles on the elements, components, and props. That's all you need
- Compile-time styles processing and efficient runtime
- Static styles extracting options
- Static analysis
- Combine the
css-in-js
andcss-modules
approaches or choose which fits you better - All the benefits of the PostCSS ecosystem
- Interoperable. Use it with components in React, Preact, Vue, htm.
There are some examples on the Сodesandbox:
Benchmarks
There are also some css-in-js benchmarks, that are available on the codesandbox.
Docs
npm i --save reshadow
.babelrc
{"plugins": ["reshadow/babel"]}
Check the Setup page to get more details (including setup with Create React App)
Example
import React from 'react';
import styled from 'reshadow';
import {readableColor, rgba} from 'polished';
const Button = ({
bgcolor = 'lightgray',
size = 's',
children,
...props
}) => styled`
button {
cursor: pointer;
padding: 5px 10px;
border-radius: 5px;
border: 2px solid ${bgcolor};
background-color: ${rgba(bgcolor, 0.7)};
color: ${readableColor(bgcolor)};
transition: background-color 0.5s;
&:hover {
background-color: ${rgba(bgcolor, 0.9)};
}
}
/**
* Match on the 'disabled' prop,
* not the DOM attribute
**/
button[disabled] {
opacity: 0.5;
pointer-events: none;
}
/**
* Match on the 'use:size' prop
*/
button[use|size='s'] {
font-size: 12px;
}
/* The 'use' namespace can be omitted */
button[|size='m'] {
font-size: 14px;
}
`(
/* use:size property would not pass to the DOM */
<button {...props} use:size={size}>
{children}
</button>,
);
const Container = () => styled`
Button + Button {
margin-left: 10px;
}
`(
<div>
<Button size="m" bgcolor="lightgray">
lightgray
</Button>
<Button size="m" bgcolor="orange">
orange
</Button>
<Button size="m" bgcolor="rebeccapurple">
rebeccapurple
</Button>
</div>,
);
Usage
css-modules
Button/index.js
import React from 'react';
import styled from 'reshadow';
import styles from './styles.css';
export const Button = ({size, children}) => styled(styles)(
<button use:size={size}>{children}</button>,
);
Button/styles.css
button {
/* button styles */
}
button[|size='m'] {
/* button styles for the size */
}
css-in-js
import React from 'react';
import styled, {css} from 'reshadow';
const anotherStyles = css`
button[disabled] {
/* disabled button styles */
}
`;
export const Button = ({size, children}) => styled(
props.another && anotherStyles,
)`
button {
/* button styles */
}
button[|size='m'] {
/* button styles for the size */
}
`(<button use:size={size}>{children}</button>);
Setup
Macro
With CRA 2 (Create React App) or babel-plugin-macros usage you can just use reshadow/macro
out of the box.
import React from 'react';
import styled from 'reshadow/macro';
export const Button = ({children}) => styled`
button {
/* button styles */
}
`(<button>{children}</button>);
Options (via babel-plugin-macros config) are the same as reshadow
babel options, but with different defaults:
option | default value |
---|---|
postcss | true |
files | /.shadow.css$/ |
Babel
Add reshadow/babel
to the plugin list.
babel.config.js
module.exports = {
plugins: ['reshadow/babel'],
};
Options
option | type | default value | description |
---|---|---|---|
postcss | boolean | {plugins: Plugin[]} | false | Use PostCSS to process CSS code. You can add your custom PostCSS plugins (they should be sync) |
files | boolean | RegExp | false | Resolve and process css files imports that match to the RegExp |
elementFallback | boolean | string | 'div' | Use fallback for the custom elements |
PostCSS
Add reshadow/postcss
to the plugin list.
postcss.config.js
module.exports = {
plugins: ['reshadow/postcss'],
};
Webpack
Use reshadow/webpack/loader
to extract styles in separate files.
webpack.config.js
{
test: /\.js$/,
use: [
'reshadow/webpack/loader',
'babel-loader',
]
}
Linting
Use reshadow/eslint
if you want to have more control about reshadow
usage.
Rules:
Prettier
Use reshadow/prettier
if you want to improve your Developer Experience with prettier.
prettier.config.js
module.exports = {
plugins: ['reshadow/prettier'],
};
Special Thanks
- Pavel Masalsky @pavelrevers
- Anton Kastritskiy @antonk52
- Petr Ermishkin @quasiyoke