How we abandoned the use of the Styled-System to create components and invented our own bike

Hello everyone! My name is Sasha, I am a co-founder and part-time chief developer at Quarkly. In this article I want to talk about how the concept of atomic CSS, which we adhere to, coupled with the shortcomings of the Styled-System functionality (and Rebass, as a special case of using this library) encouraged us to create our own tool, which we called Atomize.

A small preamble. Our project Quarkly – This is a mix of a graphical editor (like Figma, Sketch) and a site designer (like Webflow) with the addition of the functionality inherent in the classic IDE. About Quarkly, we will write a separate post, there is something to tell and what to show, but today we will talk about the Atomize mentioned above.

Atomize is the basis of the entire project and allows us to solve problems that would be impossible or difficult to solve using Styled-System and Rebass. At a minimum, the solution would be much less elegant.

If there is little time to overpower the entire post now, then we can more easily familiarize yourself with Atomize on our website. Github.

And to make the acquaintance more pleasant, we are launching a competition for assembling react components using Atomize. More on this at the end of the post.

How it all began

Starting to develop Quarkly, we agreed that we want to give our user the ability to typeset on components, but without the need to use a separate CSS file. To make the code as minimalistic as possible, but retain all the CSS features, in contrast to inline styles.

The task is not innovative and, at first glance, is completely solved with the help of the Styled-System and Rebass. But this functionality was not enough for us, and in addition we encountered the following problems:

  • uncomfortable work with breakpoints;
  • lack of the ability to write styles for the state hover, focus etc;
  • The mechanism of working with topics seemed to us not flexible enough.

What is Atomize (briefly)

image

Of the key features of Atomize, we can highlight the following:

  • the ability to use variables from the topic in composite css-properties;
  • support for hover and any other pseudo-classes;
  • short aliases for each property (as in emmet);
  • the ability to specify styles for a specific breakpoint, while maintaining readability of the markup;
  • minimalistic interface.

Atomize has two main purposes:

  • creating components that support atomic CSS and themes;
  • creating widgets for interactive editing in the Quarkly project.

Atomize instructions for use

Before you begin, you must establish the dependencies:

npm i react react-dom styled-components @quarkly/atomize @quarkly/theme

Atomize is a wrapper around the styled-component and has a similar API. It is enough to call the method with the name of the required element:

import atomize from '@quarkly/atomize';
 
const MyBox = atomize.div();

At the output, we get a react component that can accept any CSS as props.
For ease of use, a system of property aliases was developed. For example, bgc === backgroundColor

ReactDOM.render(, root);

A complete list of properties and aliases is available. here.

React inheritance mechanism is also provided:

const MySuperComponent = ({ className }) => {
   // some logic here
   return 
; }; const MyWrappedComponent = atomize(MySuperComponent);

Work with themes

About this, it seems to me, it is necessary to tell in more detail. Themes in Quarkly are based on CSS variables. The key feature is the ability to reuse variables from both the props and the topic itself, without the need for additional abstractions in the form of template functions and subsequent additional processing by the user.

To use variables from the topic, it is enough to describe the property in the topic and refer to this property using the prefix “-“.

Variables can be used as in JSX:

import Theme from "@quarkly/theme";
 
const theme = {
   colors: {
       dark: "#04080C",
   },
};
export const MyComp = () => (
   
       
   
);

(Color # 04080C is available through the –colors-dark property)

So in the subject itself:

import Theme from "@quarkly/theme";
 
const theme = {
   colors: {
       dark: "#04080C",
   },
   borders: {
       dark: "5px solid --colors-dark",
   },
};
export const MyComp = () => (
   
       
   
);

(We reused the variable from the colors, connecting it to the borders theme)

JSX markup provides a simplified syntax for colors:

import Theme from "@quarkly/theme";
 
const theme = {
   colors: {
       dark: "#04080C",
   },
};
export const MyComp = () => (
   
       
   
);

For work with media expressions, themes have a breakpoint.
You can add a prefix to any property in the form of a breakpoint key name.

import Theme from "@quarkly/theme";
 
const theme = {
   breakpoints: {
       sm: [{ type: "max-width", value: 576 }],
       md: [{ type: "max-width", value: 768 }],
       lg: [{ type: "max-width", value: 992 }],
   },
   colors: {
       dark: "#04080C",
   },
   borders: {
       dark: "5px solid --colors-dark",
   },
};
export const MyComp = () => (
   
       
   
);

Source code for topics is available. here.

Effects

The main difference between Atomize and Styled-System are the “effects”. What is it and why is it needed?
Let’s imagine that you create a Button component, change its color and border, but how to assign styles to hover, focus etc? Here the effects come to the rescue.

When creating a component, just transfer the object with the configuration:

const MySuperButton = atomize.button({
 effects: {
   hover: ":hover",
   focus: ":focus",
   active: ":active",
   disabled: ":disabled",
 },
});

The key is the prefix in the props name, and the value is the CSS selector. Thus, we closed the need for all pseudo-classes.

Now if we specify the hover prefix to any CSS property, then it will be applied with a certain effect. For example, when you hover over:

ReactDOM.render(, root);

You can also combine effects with media expressions:

ReactDOM.render(, root);

A few examples

To visualize the information above, let’s now assemble some interesting component. We have prepared two examples:

In the second example, we used most of the functionality, as well as an external API.

But that’s not all

The second purpose of Atomize, as you mentioned above, is to create widgets in Quarkly based on custom react components.

To do this, just wrap your component in Atomize and describe its configuration so that Quarkly can understand what properties can be interactively edited:

export default atomize(PokemonCard)(
 {
   name: "PokeCard",
   effects: {
     hover: ":hover",
   },
   description: {
     // past here description for your component
     en: "PokeCard — my awesome component",
   },
   propInfo: {
     // past here props description for your component
     name: {
       control: "input",
     },
   },
 },
 { name: "pikachu" }
);

The configuration fields for the component look like this:

  • effects – defines browser pseudo-classes (hover, focus, etc);
  • description – a description of the component that will appear when you hover over its name;
  • propInfo – configuration of controls that will be displayed in the right panel (props tab).

How to determine the props that will be displayed on the right panel (props tab):

propInfo: {
   yourCustomProps: { // имя свойства
       description: { en: "test" }, // описание с учетом локализации
       control: "input" // тип контрола
   }
}

Possible control options:

  • input
  • select
  • color
  • font
  • shadow
  • transition
  • transform
  • filter,
  • background
  • checkbox-icon,
  • radio-icon,
  • radio-group
  • checkbox.

One more example. Here we added our component to the system and now we can edit it interactively:

Thanks to those who mastered the material to the end! I apologize in advance for the confusion, this is the first experience in writing such articles. I would be grateful for the criticism.

And now the competition!

In order to slightly warm the community’s interest in a closer acquaintance with Atomize, we decided to follow the simple and understandable (like Atomize itself) path – we are launching a contest!

All information on the terms, rules and prizes is available at official website competition.

In short: to participate and win, you need to come up with (or find a ready-made) interesting and useful component on React and adapt it to the requirements of Atomize. We will select and award the winners in several categories at once. Additional prizes from our team in case of adding your component to Quarkly are guaranteed.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *