CSS in TS

CSS-in-TS(/JS)

In this section I'm going to present vs with CSS-in-JS flavour. CSS-in-JS is popular these days and are being used almost in every project.

But before we start I would like to present some of the article worth reading on CSS-in-JS.

  1. Why CSS-in-JS? (opens in a new tab)
  2. CSS: Isolation vs Abstraction (opens in a new tab)

There are many popular CSS-in-JS framework these days. Emotion.js (opens in a new tab) is among the top choice of css-in-js framework but what we are going to use in this example is something that I've built in past. It is called styler.

Styler (opens in a new tab) is a CSS-in-JS library with tiny bundle size and high performance benchmarks. It is a prefect choice as alternative to emotion css to be used in you next side projects. Here are some articles in case you are interseted in understaind how library like emotion work under the hood.

  1. Build your own emotion like CSS-in-JS library (opens in a new tab)
  2. Extending our CSS-in-JS to support style-component syntax (opens in a new tab)

Enough with self promotions 😛, let's get started.

button.vs.ts
import { GetVariantProps, vs } from "@vtechguys/vs";
 
// (1) CSS-in-JS style definations: style object
const styles = {
  btn: {
    display: "inline-block",
    marginBottom: "0",
    fontWeight: "400",
    textAlign: "center",
    whiteSpace: "nowrap",
    verticalAlign: "middle",
    touchAction: "manipulation",
    cursor: "pointer",
    backgroundImage: "none",
    border: "1px solid transparent",
    padding: "6px 12px",
    fontSize: "14px",
    lineHeight: "1.42857143",
    borderRadius: "4px",
    userSelect: "none"
  },
  btnDefault: {
    color: "#333",
    backgroundColor: "#fff",
    bordercolor: "#ccc"
  },
  btnColorPrimary: {
    color: "#fff",
    backgroundColor: "#337ab7",
    borderColor: "#2e6da4"
  },
 
  btnColorSecondary: {
    color: "#fff",
    backgroundColor: "#f0ad4e",
    borderColor: "#eea236"
  },
 
  btnSizeSmall: {
    padding: "0.25rem 0.5rem",
    fontSize: "0.875rem",
    borderRadius: "0.2rem"
  },
 
  btnSizeMedium: {
    padding: "0.5rem 1rem",
    fontSize: "1.25rem",
    borderRadius: "0.3rem"
  }
};
 
// (2) creating component styles from the vs config
export const button = vs({
  base: styles.btn,
  variants: {
    color: {
      default: styles.btnDefault,
      primary: styles.btnColorPrimary,
      secondary: styles.btnColorSecondary
    },
    size: {
      small: styles.btnSizeSmall,
      medium: styles.btnSizeMedium
    }
  },
  // (3) default values of variants if nothing is passed
  defaultVariants: {
    color: "default",
    size: "medium"
  }
});
 
export type ButtonVariantProps = GetVariantProps<typeof button>;

Now let's see the use in a React component.

button.component.tsx
import React from "react";
import { css } from "@vtechguys/css";
import { button, ButtonVariantProps } from "./button.vs";
 
type ButtonOwnProps = {
    // ... some button props ...
};
 
type ButtonProps = React.PropsWithChildren<ButtonVariantProps & ButtonOwnProps>;
 
export function Button(props: ButtonProps) {
    const { color, size, children, ...rest } = props;
    
    const styles = button({ color, size });
 
    const className = css(styles);
 
    return <button className={className} {...rest}>{children}</button>
}

You can create a custom hook for the styles like following:

useButtonStyles.hooks.ts
import { css } from "@vtechguys/css";
import clsx from "clsx";
import { button, ButtonVariantProps } from "./button.vs";
 
export function useButtonStyles(props: ButtonVariantProps) {
    const { color, size } = props;
 
    // you can proabably merge following useMemo into one
    const styles = useMemo(() => button({ color, size }), [color, size]);
 
    const className = useMemo(() => css(styles), styles)
 
    return className;
}