DEV Community

Jonathan Gerbaud
Jonathan Gerbaud

Posted on • Updated on

React & CSS : The readability argument

In a previous post, I described my new CSS-IN-JS framework for React, named Soperio UI, where I'm trying to "get rid off" CSS. You can read more about it here.

A quick link to my new framework if you want to understand a bit better what kind of "system" I'm trying to offer devs to improve their coding experience with React and styling:
https://www.soperio-ui.com

Since then, I've heard a few people giving me feedback like:

Hey, your new framework is awesome! However, one advantage of CSS is that, it allows separation of styles in a different file, that increases the code readability.

I was a bit surprised as I personally dislike CSS a lot, and I thought it was common ground that CSS was still something that most devs had to cope with because there was nothing better out there yet.

So let's discuss this.

The context

I'm building SaaS apps and I have a lot of component styling to do.

While I'm using a UI component framework (Valerya UI, built on top of Soperio, but could use anything else) and I do have a global theme setup for my apps, I need to quicky and easily style each and every React component of every of my app screens (that means lots of components).

File splitting

I might be crazy, but I never understood why people want so desperately to put the CSS in a separate file from a component's React code file.

Maybe that's because they want to separate the logic from the design, or because it has always been this way since the emergence of CSS, or because CSS is taking way too much space (meaning lines of code) in general, or because they want to use CSS generators like SASS or LESS.

Although this is not the subject of this article, I would like hear your thoughts about this and why you think this is a good idea.

Improves code readability, really?

So, someone told me the following:

Everything inline reduces the code readability. Secondly, css allows us to combine multiple related props in a single definition such as border: 'solid 1px black'

In this very simple case, I would agree. With Soperio, it would translate in something like this:

<div 
    border="px" // value from theme, translates to 1px
    // You can define this property althought it's "solid"
    // by default so you can omit it
    borderStyle="solid"
    borderColor="black"
>
   ... // Content of div
</div>

// or
<div border="px" borderStyle="solid" borderColor="black">...</div>
Enter fullscreen mode Exit fullscreen mode

In this use case, you get 3 props (or just 2 as you can omit borderStyle). So yeah, it's a bit more than a single line of CSS.

Real case scenario

When you're building a SaaS app, your component needs to react to states, dark mode and be responsive.

So let's write a quick component. We will build a simple card component with an image header, a title and a description. It will respond to the hover state by slightly changing its background color. It will be display as a column on mobile screens and a row on larger screens.

Image description

Image description

Let's start with Soperio first.

import { SoperioComponent } from "@soperio/react"

interface MyComponentProps extends SoperioComponent
{
  imageUrl: string,
  title: string, 
  description: string
}

function MyComponent({ imageUrl, title, description, ...props }: MyComponentProps)
{
  return (
    <div
      dflex
      flexCol
      md_flexRow
      bgColor="light"
      hover_bgColor="lightHover"
      textColor="dark"
      md_maxW="1/3"
      md_maxH="48"
      rounded
      shadow
      {...props}
    >
      <div
        bgImage={`url(${imageUrl})`}
        w="full" h="40"
        md_w="32rem" md_h="unset" md_maxH="48"
        bgSize="cover"
        bgPosition="center"
        roundedT
        mb="3"
        md_mb="0"
      />

      <div dflex flexCol pb="3" px="4">
        <div trait="typo.display5">{title}</div>
        <p 
          trait="typo.body2" 
          fontWeight="400" 
          textColor="darkSecondary" 
          mt="3"
        >
          {description}
        </p>
      </div>
    </div>
  )
}

Enter fullscreen mode Exit fullscreen mode

Okay, now let's convert this code to CSS

interface MyComponentProps
{
  imageUrl: string,
  title: string, 
  description: string,
  children?: ReactNode
}

function MyComponent({ imageUrl, title, description, className, children, ...props }: MyComponentProps)
{
  return (
    <div className={cx("mycomponent_wrapper", className)} {...props}>
      <img src={imageUrl} className="mycomponent_img" />
      <div className="mycomponent_content">
        <div className="mycomponent_title">{title}</div>
        <div className="mycomponent_desc">{description}</div>
      </div>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Okay, sure, much simpler. But let's see the CSS now. I'm using SASS syntax to get a simpler code. Assume all the variables matches the ones from the default theme in Soperio.

.mycomponent_wrapper {
    display: flex;
    flex-direction: column;
    background: $light_bg_color;
    color: $dark_text_color;
    border-radius: $default_radius_rounded;
    box-shadow: $default_shadow;

    &:hover {
        background: $light_hover_color;
    }

    .mycomponent_img {
        width: $spacing_48;
        height: 100%;
        background-size: cover;
        background-position: center;
        border-top-left-radius: $default_radius_rounded;
        border-top-right-radius: $default_radius_rounded;
        margin-bottom: $spacing_3;
    }

    .mycomponent_content {
        display: flex;
        flex-direction: column;
        padding-bottom: $spacing_3;
        padding-left: $spacing_4;
        padding-right: $spacing_4;
    }

    .mycomponent_title {
        @include typo_display5;
        padding: 0 $spacing_3 0 $spacing_3;
    }

    .mycomponent_description {
        @include typo_body1;
        color: $dark_secondary_color;
        font-weight: 400;
        margin-top: $spacing_3;
    }
}

@media(min-width: $breakpoint_md) {
    .mycomponent_wrapper {
        flex-direction: row;
        max-width: 33.33%;
        max-height: $spacing_48;
    }

    .mycomponent_img {
        width: $spacing_64;
        height: unset;
        max-height: $spacing_32;
        margin-bottom: 0px;
    }
}
Enter fullscreen mode Exit fullscreen mode

Now, now, less simple isn't it! If you compare this code with the one used with Soperio, which one would you say is the most readable?

And this is quite a simple component. We don't have multiple breakpoints, nor different hover states on breakpoints, or disabled states for example.

The more styling, the more CSS code. Same is true with Soperio, but you add less lines of code than with CSS.

For me, the choice is obvious and I would choose Soperio over SASS. But maybe you don't see it that way so let me know if you disagree.

Conclusion

I'm personally convinced that when building SaaS apps, it's actually more readable to use Soperio CSS-IN-JS than CSS (or rather SASS/LESS as it would be even longer to write -and read- CSS...).

This post was about readability. I could write about some other advantages about Soperio properties over CSS, because readability is not everything we have to take into account, but that's for another blog post!

Top comments (0)