DEV Community

Cover image for Freak out! Showcasing Chic Modules 1.0 ✨ A Styled-like CSS-Modules API
Liam Howell
Liam Howell

Posted on

Freak out! Showcasing Chic Modules 1.0 ✨ A Styled-like CSS-Modules API

A familiar styled-like API for working with css-modules in React

Another week, another announcement. While the wind may have been taken out of my sails by Facebook talking about their own styling solution, I'm pleased to announce that my own take on managing components styles in React has reached stable status. Introducing Chic Modules!

What is chic-modules

While I adore the styled pattern for composing React components, I also love css-modules and separating concerns. Life isn't all sunshine and roses though. Complex class compositions often result in ugly inline ternary operators for conditional class names and style modifiers. I wanted to create a compromise, or "best-of-both-worlds" solution, that wraps a standard css-modules implementation in a well-established API.

This project isn't meant to supersede others like styled-components, and doesn't attempt to join the conversation around css-in-js vs css-modules (there's literally thousands of articles for that), it's simply meant to be a different solution and alternative approach. My attitude is, if you're going to use css-modules anyway then why not give chic-modules a whirl.

Features

  • 🧠 Intelligent prop-based style modifiers
  • 🤝 Extending/sharing styles between components
  • ⛓ Static prop management via attrs constructor
  • 🏃‍♂️ Dynamic run-time style management
  • 🔎 Full TypeScript support

Basic Example

// application.module.css

.wrapper {
  padding: 4em;
  background: papayawhip;
}

.title {
  font-size: 1.5em;
  text-align: center;
  color: palevioletred;
}
Enter fullscreen mode Exit fullscreen mode
// application.jsx

import React from 'react';

import styles from './application.module.css';

import { create } from 'chic-modules';

// Call the chic-modules `create` factory and pass the
// required styles object as an argument
const styled = create(styles);

// Create a <Wrapper> React component that inherits the `.wrapper`
// class from the styles object and renders a <section> html element
const Wrapper = styled.section('wrapper');

// Create a <Title> React component that inherits the `.title`
// class from the styles object and renders a <h1> html element
const Title = styled.h1('title');

// Use them like regular React components – except they're styled!
function Application() {
  return (
    <Wrapper>
      <Title>Hello World, this is my first chic component!</Title>
    </Wrapper>
  );
}
Enter fullscreen mode Exit fullscreen mode

This is what you'll see in your browser:

Chic Modules example usage

Open in CodeSandbox

Style Modifiers

As I briefly touched upon in the opening statement, my biggest gripe when using css-modules is the cumbersome nature of adding "modifier" class names to components. Where I believe chic-modules really shines is in its attempt to solve this problem.

Taking a look at this pretty standard setup using the classnames package, you can see that a lot of extra steps are required to attach conditional class names to a component. This problem only gets worse when you try to go it alone without a class name utility package.

🙅‍♀️ Cumbersome

import classnames from 'classnames';
import styles from './button.module.css';

function MyButton({ children, isPrimary }) {
  const classes = classnames(
    'button',
    {
      [styles['button--primary']]: isPrimary
    }
  );

  return <button classNames={classes}>{children}</button>;
}

// outputs <button class="button button--primary">
Enter fullscreen mode Exit fullscreen mode

On the other hand, chic-modules can infer when a prop is being used as a style modifier and automagically add the relevant modifier class if it exists in the styles object to the component.

😎 Chic

import styles from './button.module.css';
import { create } from 'chic-modules';

const styled = create(styles);
const Button = styled.button('button');

function MyButton({ children, isPrimary }) {
  return <Button isPrimary={isPrimary}>{children}</Button>;
}

// outputs <button class="button button--primary">
Enter fullscreen mode Exit fullscreen mode

Any prop can be used to infer a style modifier as long as it starts with has, is or with and its value evaluates as truthy. You can also pass string values to props prefixed with with and have that value used in the constructed modifier class.

chic-modules expects that your styles follow the BEM naming convention, so when using this package ensure that your stylesheet aligns with this structure.

<Button hasBorder isPrimary withTextColor="black" />
// outputs <button class="button button--border button--primary button--text-color-black">
Enter fullscreen mode Exit fullscreen mode

Documentation

Interested? Read the full documentation here.

The Future / Helping Out

My main focus for the project at the moment is performance improvements over additional features. I think the initial feature-set is in a good place and I would like to get more insights on any real world usage before thinking about adding more. There's also definitely parts of the code base that could do with being fine-tuned and abstracted a little more.

If you find chic-modules interesting and would like to help out then feel free to take a look over the code and suggest any improvements. Additionally, it would be a big help if you could star, tweet or mention this project to raise some awareness!

And of course, if you do end up building anything with chic-modules then definitely send it my way! I'd love to see what's being made and I'll even include it in the README.

Thanks for your time.

C'est chic!

https://github.com/eels/chic-modules

Top comments (2)

Collapse
 
byme8 profile image
Stanislav Silin

What happens if you type the wrong class name? I tested the sandbox that you provided, and it looks like it just silently fails, which is not a great idea. There are a lot of modern frameworks that can fail on compilation time. So, in this case, it is not clear what benefits your library provides.

Collapse
 
eels profile image
Liam Howell

That's a great catch! As you noticed it currently just fails silently, but still returns the underlying html element and additional props. Definitely an oversight on my part and should be flagged during compilation to let the developer know. I'll add it to my bug tracker. Thanks for the input!