This is the third post on a series on how to make your own UI React Library.
What are we going to do?
- Add support for CSS Modules compilation to our builder.
- Add support for CSS Modules in Storybook.
- Enhance the styles of our UI Components similar to what you would do on a Design System.
CSS Modules
CSS Modules are great because it lets you consume css in your components that can be locally scoped with auto-generated classes, this is great to prevent collision between classes.
Let's start adding rollup-plugin-postcss
lerna add rollup-plugin-postcss --scope=@cddev/phoenix-builder
Now it's just a matter of importing the plugin and using it on the input configuration with modules: true
option.
phoenix-builder/lib/phoenix-builder.js
// At the top after other imports
const postcss = require('rollup-plugin-postcss');
// Adding a new plugin with `modules: true`
const inputOptions = {
// ... other options
plugins: [
postcss({
// Key configuration
modules: true,
}),
// ... after other options
],
};
Let's add some css in our phoenix-button
to test this feature.
First create a styles.css
next to the phoenix-button.js
phoenix-button/lib/styles.css
.Button {
background-color: red;
}
After this you should be able to import it in your the button and use it
phoenix-button/lib/phoenix-button.js
import React from 'react';
import styles from './styles.css';
const Button = ({ children }) => <button className={styles.Button}>{children}</button>;
export { Button };
You can see above that in order to use the css modules you import the styles and then access the class like styles.Button
as if the class became a property of styles
object.
Running npm run build
should compile the component as before but adding some new code to inject the css.
Add support for CSS Modules in storybook
We can't proceed without looking at what we are doing in terms of styles and by just importing css on the components and then on storybook it won't work, so we need to add support for css-modules on storybook.
Luckily we have almost everything setup so we just need to do a small override on the storybook webpack configuration in
.storybook/main.js
:
module.exports = {
stories: ['../packages/**/*.stories.js'],
addons: ['@storybook/addon-actions', '@storybook/addon-links'],
webpackFinal: async (config) => {
// remove default css rule from storybook
config.module.rules = config.module.rules.filter((f) => f.test.toString() !== '/\\.css$/');
// push our custom easy one
config.module.rules.push({
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
// Key config
modules: true,
},
},
],
});
// Return the altered config
return config;
},
};
Voila!
Now you can npm run storybook
and you should see your first react component using CSS Modules
Enhancing the Button Component
This guide won't be almost finished without adding some fanciness; In this case, we're going to borrow some styles and Design System from https://www.coinbase.com/, because why not.
From their homepage we can see they have mainly two buttons: one green and one with a white outline, let's create the css for those.
phoenix-button/lib/styles.css
.Button {
background-color: #05b169;
border-radius: 0.25rem;
border: 1px solid #05b169;
color: #fff;
cursor: pointer;
font-size: 1rem;
padding: 0.75rem 1rem;
transition: all 100ms ease-in-out;
width: auto;
outline: none;
}
.Button:hover,
.Button:focus {
background-color: #00a55e;
border-color: #00a55e;
}
.ButtonSecondary {
background: transparent;
border-color: #fff;
}
.ButtonSecondary:hover,
.ButtonSecondary:focus {
background: #fff;
border-color: #fff;
color: #000;
}
Now for the code in the button:
phoenix-button/lib/phoenix-button.js
import React from 'react';
import cx from 'clsx';
import styles from './styles.css';
const Button = ({ children, className, variant, ...rest }) => {
const classes = cx(
styles.Button,
{
[styles.ButtonSecondary]: variant === 'secondary',
},
className
);
return (
<button {...rest} className={classes}>
{children}
</button>
);
};
export { Button };
And then enhancing our stories like this:
phoenix-button/docs/phoenix-button.stories.js
import React from 'react';
import { Button } from '../lib/phoenix-button';
export default { title: 'Button' };
export const primary = () => <Button>Hello Button</Button>;
export const secondary = () => (
<div style={{ background: '#1652f0', padding: 12 }}>
<Button variant="secondary">Hello Button</Button>
</div>
);
Now you should be able to see some variants of your fancy button
Enhancing the Text Component
We are just going to grab a couple of their sizes in their stack and not use their proprietary font.
phoenix-text/lib/styles.css
.Text {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell,
'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
font-size: 0.875rem;
font-weight: 400;
line-height: 1.5;
}
.Hero {
font-size: 3rem;
font-weight: 800;
line-height: 3.25rem;
}
.Heading {
font-size: 2.5rem;
font-weight: 500;
}
phoenix-text/lib/phoenix-text.js
import React from 'react';
import cx from 'clsx';
import styles from './styles.css';
const Text = ({ children, className, as = 'p', variant, ...rest }) => {
const textVariant = styles[variant] || 'Body';
console.log(textVariant);
const classes = cx(
styles.Text,
{
[textVariant]: variant,
},
className
);
return React.createElement(
as,
{
...rest,
className: classes,
},
children
);
};
export { Text };
phoenix-text/lib/phoenix-text.stories.js
import React from 'react';
import { Text } from '../lib/phoenix-text';
export default { title: 'Text' };
export const Body = () => <Text>Body Text</Text>;
export const Hero = () => <Text variant="Hero">Hero Text</Text>;
export const Heading = () => <Text variant="Heading">Heading Text</Text>;
Conclusion
You know have CSS Modules support both for your compiled code as well as your storybook; With this it will be a little bit more difficult to have collisions on the auto generated classes and you can even go one step further and provide the source code so your clients compile the code and generate the classes and styles themselves.
Resources
Code: https://github.com/davixyz/phoenix/tree/part3
Github: https://github.com/davixyz
Twitter: https://twitter.com/carloscastrodev
Top comments (1)
Hi Carlos i'm not able to import css like this
import "./styles.css";
can you please explain why it's happening?
And another thing when i use rollup newer version after publishing it doesn't import css