One of the tricky things about writing React components meant for public consumption is making them compatible with various styling approaches used by the community. The problem exists because application styling isn't considered as a first-class citizen by React and it doesn't provide a strong opinion on how to solve it. As a result, the amount of available approaches has exploded.
Jan-Felix Schwarz noticed the same problem. As a result substyle was born.
I work as front-end tech lead at Signavio in Berlin. We are building products that help large businesses to understand and transform the ways they work. I've been doing JavaScript SPA development for the best part of the past decade, so I guess when React came out it was a defining moment in my professional life. :)
substyle is a utility for authors of open source React component libraries. It tries to make it easier to build components in a way that allows users to customize styles of every single element rendered by a component. Users will be able to do that through CSS, CSS Modules, many css-in-js libraries, or using inline styles. This way, the component integrates well into applications using any styling approach, without forcing an opinion about tooling.
substyle provides a higher-order component that preprocesses whichever props the user passes for styling purposes so that they become more comfortable to consume. It injects a single, special style
prop, which is used in the wrapped component's render function to derive the right styling props to forward to each of the rendered elements.
For example, a universally stylable <Popover />
component could be written like this:
import substyle from "substyle";
const Popover = substyle(({ style, children }) => (
<div {...style}>
<button {...style("close")}>x</button>
{children}
</div>
));
Now, users of the <Popover />
component can pass their custom className
, which will be used to derive classes for all the elements rendered by the component:
// JSX // Rendered HTML
<Popover className="popover">
{" "}
// <div class="popover">
<span>Hello world!</span> //{" "}
<button class="popover__close"></Popover> // x //{" "}
</button>
// <span>Hello world!</span>
//{" "}
</div>
If they want to pass some custom inline styles, they can do so by supplying a nested style
object:
// JSX // Rendered HTML
<Popover style={{ // <div style="background: white;">
background: 'white', // <button style="right: 0;">x</button>
close: { right: 0 }, // <span>Hello world!</span>
}}> // </div>
<span>Hello world!</span>
</Popover>
If they use css modules or some css-in-js lib, they will want to pass the unique, auto-generated classes to assign to the elements. They can do so via the classNames
prop that is handled by substyle:
// JSX // Rendered HTML
<Popover classNames={{ // <div class="1n3n1g">
popover: '1n3n1g', // <button class="ew339k">x</button>
popover__close: 'ew339k', // <span>Hello world!</span>
}}> // </div>
<span>Hello world!</span>
</Popover>
I know of one other solution addressing the same problem called react-themeable. The general idea behind both, react-themeable and substyle, is the same. However, during the development of a component library at Signavio I had to solve some additional practical challenges:
Exploring solutions to these problems I finally ended up writing my utility.
I got the initial idea for it while developing an open source React mentions input. As I was aiming to let users style this input widget with css and inline styles, I had to add quite a bit of code to my components just for this purpose. To keep my code DRY and the render functions clean, I extracted this repetitive styling logic into a helper function.
Later I realized that I could quickly add support for styling through css modules and css-in-js libraries, just by changing this helper function and without having to touch any of the components. And this is basically how substyle came to be.
I hope that the idea of supporting universal styling takes hold in the React community and that we can establish some best practices for writing reusable components. It would make app developers' lives better as they would not have to study docs, examples, or source code of every single component library to find out how to override styles of particular elements. Instead, they could just use the same familiar styling API for any open source component.
substyle is just my take on a universal styling API for React components and it demonstrates that it is quite easy to implement this. So I don't know if substyle as a library will have a future, but I hope that we will continue the discussion about the styling of reusable components.
For web development in general, I see much more fundamental trends: One hot topic is the shift from frameworks to compilers. I believe this idea has enormous potential and it's exciting to see projects like Prepack and svelte pushing forward this frontier.
Another development I expect for the next years is that the architectural boundary between client and server will become more and more blurry as server rendering and GraphQL APIs become the norm. We will be able to share much more code between front and back ends, up to a point, where this distinction is rendered useless.
Be more passionate about what you are building than how you are making it. Don't choose libraries and frameworks just because they are hyped, but because they promise to solve a particular problem that you are feeling.
I think this helps to embrace that there is so much choice in the JavaScript ecosystem, rather than feeling overwhelmed by it. Also, don't be intimidated by unfamiliar, complex-sounding jargon. Usually, it's just fancy names for simple concepts.
I dig the stuff Brent Jackson (@jxnblk) is building. He's both, a great programmer and designer, and his work is right at the intersection of both disciplines.
Thanks for the interview Jan-Felix! substyle looks like an excellent fit for anyone wanting to write robust React components that are easy to consume.
You can find substyle on GitHub. See also Jan-Felix's presentation (16 mins) on the topic.