Styling Components with React Fela

joshtronic

Styling in React comes in all shapes and sizes. Out of the box, you can assign classes via the className property or assign CSS properties by passing an object to the style property. While sufficient enough in most scenarios, they are not without their shortcomings. Making classNames dynamic requires defining additional classes, and styles, while allowing dynamic properties, still requires boilerplate code and doesn’t allow you dig deep into pseudo-class properties like :hover. That’s where Fela can come to your rescue!

Fela is a framework-agnostic library for handling state-driven styling in JavaScript. It’s highly performant and gives you some flexibility in regard to how you use it. While you can use Fela by itself, react-fela is available to provide React bindings for your React.js apps.

Getting Started

To get started, we need to add react-fela to our project:

Via npm

$ npm install --save react-fela

Or via Yarn

$ yarn add react-fela

For this article we will be using some methods from the fela library directly. Don’t worry though, react-fela includes this dependency so we should be good to go.

The Renderer

As promised, there is a part of the fela library that we will need to use, that’s createRenderer. The createRenderer method is used to create a renderer that will be passed a Provider component that will wrap out components that are leveraging Fela.

All of the following examples will include the boilerplate code that we need to make the magic happen.

Using Generated CSS Classes

The least complex Fela example isn’t ideal but does have the least amount of boilerplate code.

The way Fela works is that it takes your styles, generates the appropriate CSS with atomic classes and allows you to grab the CSS classes that can be passed to any component’s classNames property:

import React from "react";
import { render } from "react-dom";

import { createRenderer } from "fela";
import { Provider } from "react-fela";

const renderer = createRenderer();

const rule = ({
  backgroundColor = "#6db65b",
  borderColor = "#efbb35",
  padding
}) => ({
  backgroundColor: backgroundColor,
  border: `10px solid ${borderColor}`,
  color: "#fff",
  fontWeight: "bold",
  padding: `${padding}px`,
  ":hover": {
    cursor: "pointer",
    filter: "drop-shadow(0 10px 19px rgba(0, 0, 0, 0.3))"
  }
});

const container = document.createElement("div");
document.body.appendChild(container);
render(
  <Provider renderer={renderer}>
    <div className={renderer.renderRule(rule, { padding: 100 })}>
      Hover Over Me!
    </div>
  </Provider>,
  container
);

As you can see in the example, the renderer is used to generate our CSS and class names based on the object of CSS properties being passed-in.

The rule is just a simple anonymous function that returns an object with all of our properties including any properties that may have been passed-in.

Because rule is just a function with a return object, you could expand and include additional logic as you see fit instead of immediately returning the expected object.

Using Component Primitives

While the previous approach works well enough, sometimes it’s nice to create a new component that could easily be reused throughout your project.

In those scenarios, we can leverage the FelaComponent primitive component to create a new component:

import React from "react";
import { render } from "react-dom";

import { createRenderer } from "fela";
import { FelaComponent, Provider } from "react-fela";

const renderer = createRenderer();

const rule = ({
  backgroundColor = "#6db65b",
  borderColor = "#efbb35",
  padding
}) => ({
  backgroundColor: backgroundColor,
  border: `10px solid ${borderColor}`,
  color: "#fff",
  fontWeight: "bold",
  padding: `${padding}px`,
  ":hover": {
    cursor: "pointer",
    filter: "drop-shadow(0 10px 19px rgba(0, 0, 0, 0.3))"
  }
});

const PaddedContainer = ({
  backgroundColor,
  borderColor,
  padding,
  children
}) => (
  <FelaComponent
    rule={rule}
    backgroundColor={backgroundColor}
    borderColor={borderColor}
    padding={padding}
  >
    {children}
  </FelaComponent>
);

const container = document.createElement("div");
document.body.appendChild(container);
render(
  <Provider renderer={renderer}>
    <PaddedContainer padding={100}>
      Hover Over Me!
    </PaddedContainer>
  </Provider>,
  container
);

Utilizing a similar rule, we are able to create a new PaddedContainer component that we can pass properties to directly without the overhead and assigning classes via renderRule.

Creating Components Yourself

There’s nothing wrong with using primitives to create new components, but you tend to wind up with a bit more boilerplate than you would by creating components directly:

import React from "react";
import { render } from "react-dom";

import { createRenderer } from "fela";
import { createComponent, Provider } from "react-fela";

const renderer = createRenderer();

const rule = ({
  backgroundColor,
  borderColor,
  padding
}) => ({
  backgroundColor: backgroundColor,
  border: `10px solid ${borderColor}`,
  color: "#fff",
  fontWeight: "bold",
  padding: `${padding}px`,
  ":hover": {
    cursor: "pointer",
    filter: "drop-shadow(0 10px 19px rgba(0, 0, 0, 0.3))"
  }
});

const AnotherPaddedContainer = createComponent(rule);

const container = document.createElement("div");
document.body.appendChild(container);
render(
  <Provider renderer={renderer}>
    <AnotherPaddedContainer padding={100}>Hover Over Me!</AnotherPaddedContainer>
  </Provider>,
  container
);

A bit cleaner and just as reusable as our example with primitive components!

Conclusion

Regardless of which approach you take, leveraging react-fela can speed up the time necessary to dynamically style components in React by eliminating the amount of boilerplate you have to write.

To see the code samples above in action, head over to CodeSandbox.

Enjoy! 💥

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#