How to Style an app using Emotion CSS in JS

Author

Web developer

How to Style an app using Emotion CSS in JS

October 14, 2021

reactstyling

How to Style an app using Emotion CSS in JS

Introduction

This blog helps you to build simple reusable button components and you will know about how to write CSS in the Js library. And how to access the props to your component and change the styles based on props.

What is Emotion and Why Emotion ?

Emotion is a high performance, lightweight css-in-js library. It provides dynamic predictable style compositions in addition to get a experience. emotion is highly efficient, perform well and we can use each library for specific use.

Prerequisites

  • HTML
  • CSS
  • Javascript + ES6
  • React

Installation

There are two packages, one is @emotion/core and another one which powers the styled-components @emotion/styled. We will see examples for both.

# Create a project named EmotionApp

yarn add @emotion/core
yarn add @emotion/styled
         or
npm i @emotion/styled @emotion/react  #// for react application
Global styles in emotion

Before starting site styles, we always need some reset to normalize browser default styles. I am going to use normalize.css.

This is optional if you want you can go with this. This is like reset.scss. Without this also you’ll create components.

//Adding global CSS
import { Global, css } from "@emotion/core"
//importing the text from normalize.css file
import normalize from "normalize.css"

const App = () => {
  return (
    <>
      <Global
        styles={css`
          ${normalize}
          body {
            background-color: #fafafa;
          }
        `}
      >
        ...Content
      </Global>
    </>
  )
}

Here we have added the normalized CSS along with background color for the body element. We can add any common global CSS like this in emotion.

Creating a reusable button component.

Button is the most important interactive component used by the users on how to perform actions. There are different types of buttons like primary, secondary, success, large, extraLarge, info, error. we can give accents like solid, block, hallow, ghost, light. and more.

This is the config file for colors and sizes.
const config = {
  primaryColor: "#0d6efd",
  secondaryColor: "#7a7a7a",
  error: "#dc3545",
  warning: "#ffc107",
  success: "#198754",
  info: "#0dcaf0",
  hover: "#008FCB",
  textColor: "black",
  lightColor: "#F9F9F9",
  borderColor: " #DDDDDD",
  borderRadius: "4px",
  borderWidth: "1px",
  border: "1px solid",
  buttonColorPrimary: "#fff",
  buttonColorSecondary: "#fff",
  defaultSpacing: "8px",
  smSpacing: "5px",
  lgSpacing: "16px",
  xlSpacing: "24px",
  defaultFontsize: "16px",
  smFontsize: "13px",
  lgFontsize: "18px",
  xlFontsize: "22px",
  transaprantBackground: "transparent",
}
export const tokens = {
  colors: {
    primary: `${config.primaryColor}`,
    hover: `${config.hover}`,
    error: `${config.error}`,
    info: `${config.info}`,
    success: `${config.success}`,
    warning: `${config.warning}`,
    secondary: `${config.secondaryColor}`,
    borderColor: `${config.borderColor}`,
    buttonColorPrimary: `${config.buttonColorPrimary}`,
    buttonColorSecondary: `${config.buttonColorSecondary}`,
    lightColor: `${config.lightColor}`,
    textColor: `${config.textColor}`,
    transaprantBackground: `${config.transaprantBackground}`,
    border: `${config.border}`,
    white: "#ffffff",
    black: "#000000",
  },
  backgroundColor: {
    default: "black",
    light: "lightblue",
    dark: "darkblue",
  },
  font: {
    fontSize: {
      default: `${config.defaultFontsize}`,
      sm: `${config.smFontsize}`,
      lg: `${config.lgFontsize}`,
      xl: `${config.xlFontsize}`,
    },
    fontWeight: {
      normal: "400",
      bold: "700",
      extrabold: "900",
    },
    fontFamily: {
      sans: ['"source sans pro"', "helvetica", "arial", "sans-serif"],
      mono: ['"source code pro"', "monospace"],
    },
  },
  spacing: {
    default: `${config.defaultSpacing}`,
    sm: `${config.smSpacing}`,
    lg: `${config.lgSpacing}`,
    xl: `${config.xlSpacing}`,
  },
  position: {
    static: "static",
    relative: "relative",
    absolute: "absolute",
    fixed: "fixed",
    sticky: "sticky",
  },
  positionValue: {
    top: "",
    bottom: "",
    left: "",
    right: "",
  },

  borderRadius: {
    none: "0",
    default: `${config.borderRadius}`,
    md: "4px",
    lg: "15px",
    round: "50%",
  },
  maxWidths: {
    small: "544px",
    medium: "768px",
    large: "1012px",
    xlarge: "1280px",
  },
  letterSpacing: {
    normal: "0",
    wide: "0.2px",
  },
  lineHeight: {
    none: "1",
    normal: "1.5",
    tight: "1.25",
    loose: "2",
  },
  listStyleType: {
    none: "none",
    disc: "disc",
    decimal: "decimal",
  },
  size: {
    large: "large",
    medium: "medium",
    small: "small",
  },
}

Component

import React from "react"
import { tokens } from "./Tokens"
import styled from "@emotion/styled"
import { css } from "@emotion/react"

const EmotionButton = styled.button`
  border-radius: ${tokens.borderRadius.default};
  background-color: ${tokens.colors.primary};
  color: ${props =>
    props.secondary
      ? tokens.colors.buttonColorSecondary
      : tokens.colors.buttonColorPrimary};
  padding: ${tokens.spacing.default} ${tokens.spacing.lg};
  font-size: ${props => {
    if (props.big) return "20px"
    return `${tokens.font.fontSize.default}`
  }};
  display: ${props => (props.block === "block" ? "block" : "")};
  width: ${props => (props.block === "block" ? "100%" : "")};
  &:hover {
    box-shadow: inset 0 0 0 100em rgb(0 0 0 / 10%);
  }
  outline: none;
  border: none;
  cursor: pointer;
  ${props => {
    return (
      props.disabled &&
      css`
        :disabled {
          opacity: 0.4;
          pointer-events: none;
        }
      `
    )
  }}

  ${props => {
    return (
      props.rounded &&
      css`
        border-radius: ${props.rounded + "px"};
      `
    )
  }}
  ${props => {
    return (
      props.size === "small" &&
      css`
        padding: ${tokens.spacing.sm};
        font-size: ${tokens.font.fontSize.sm};
      `
    )
  }}
  ${props => {
    return (
      props.size === "medium" &&
      css`
        padding: ${tokens.spacing.lg};
        font-size: ${tokens.font.fontSize.lg};
      `
    )
  }}
  ${props => {
    return (
      props.size === "large" &&
      css`
        padding: ${tokens.spacing.xl};
        font-size: ${tokens.font.fontSize.xl};
      `
    )
  }}
  ${props => {
    return (
      props.size &&
      css`
        padding: ${props.size / 2 + "px"} ${props.size + "px"};
        font-size: ${props.size + "px"};
      `
    )
  }}

${props => {
    return (
      props.accent === "secondary" &&
      css`
        background: ${tokens.colors.secondary};
        color: ${tokens.colors.buttonColorSecondary};
      `
    )
  }};
  ${props => {
    return (
      props.accent === "primary" &&
      css`
        background: ${tokens.colors.primary};
        color: #fff;
      `
    )
  }};
  ${props => {
    return (
      props.accent === "warning" &&
      css`
        background: ${tokens.colors.warning};
        color: #fff;
      `
    )
  }};
  ${props => {
    return (
      props.accent === "success" &&
      css`
        background: ${tokens.colors.success};
        color: #fff;
      `
    )
  }};
  ${props => {
    return (
      props.accent === "info" &&
      css`
        background: ${tokens.colors.info};
        color: #fff;
      `
    )
  }};
  ${props => {
    return (
      props.accent === "error" &&
      css`
        background: ${tokens.colors.error};
        color: #fff;
      `
    )
  }};
  ${props => {
    return (
      props.type === "light" &&
      css`
        color: ${props.color ? props.color : "#fff"};
        border: 1px solid ${props.color
            ? props.color
            : tokens.colors.primary && props.accent === "secondary"
            ? tokens.colors.secondary
            : tokens.colors.primary && props.accent === "error"
            ? tokens.colors.error
            : tokens.colors.primary && props.accent === "info"
            ? tokens.colors.info
            : tokens.colors.primary && props.accent === "warning"
            ? tokens.colors.warning
            : tokens.colors.primary && props.accent === "success"
            ? tokens.colors.success
            : tokens.colors.primary};
      `
    )
  }};
  ${props => {
    return (
      props.type === "ghost" &&
      css`
        background: ${tokens.colors.transaprantBackground};
        color: ${props.color
          ? props.color
          : tokens.colors.primary && props.accent === "secondary"
          ? tokens.colors.secondary
          : tokens.colors.primary && props.accent === "error"
          ? tokens.colors.error
          : tokens.colors.primary && props.accent === "info"
          ? tokens.colors.info
          : tokens.colors.primary && props.accent === "warning"
          ? tokens.colors.warning
          : tokens.colors.primary && props.accent === "success"
          ? tokens.colors.success
          : tokens.colors.primary};
        border: none;
      `
    )
  }};
  ${props => {
    return (
      props.type === "hallow" &&
      css`
        background: ${tokens.colors.transaprantBackground};
        color: ${props.color
          ? props.color
          : tokens.colors.primary && props.accent === "secondary"
          ? tokens.colors.secondary
          : tokens.colors.primary && props.accent === "error"
          ? tokens.colors.error
          : tokens.colors.primary && props.accent === "info"
          ? tokens.colors.info
          : tokens.colors.primary && props.accent === "warning"
          ? tokens.colors.warning
          : tokens.colors.primary && props.accent === "success"
          ? tokens.colors.success
          : tokens.colors.primary};
        border: 1px solid ${props.color
            ? props.color
            : tokens.colors.primary && props.accent === "secondary"
            ? tokens.colors.secondary
            : tokens.colors.primary && props.accent === "error"
            ? tokens.colors.error
            : tokens.colors.primary && props.accent === "info"
            ? tokens.colors.info
            : tokens.colors.primary && props.accent === "warning"
            ? tokens.colors.warning
            : tokens.colors.primary && props.accent === "success"
            ? tokens.colors.success
            : tokens.colors.primary};
      `
    )
  }}
`

const Button = ({ ...props }) => {
  return (
    <EmotionButton
      {...props}
      style={{ ...props }}
      onClick={e => props.onClick(e)}
    >
      {props.label}
    </EmotionButton>
  )
}

export default Button

Usage

Here how you gonna use button component
import Button from "./Button"

function App() {
  return (
    <>
      <div className="app">
        <Button label="Rounded" rounded="50" accent="primary" />

        <Button label="Primary" type="hallow" accent="primary" />

        <Button label="Secondary" accent="secondary" />

        <Button label="ghost" accent="secondary" type="ghost" />

        <Button label="Error" size="large" accent="error" />

        <Button label="Info" accent="info" />

        <Button label="Warning" accent="warning" />

        <Button label="Success" accent="success" />

        <Button label="Block" block="block" accent="warning" />
      </div>
    </>
  )
}

export default App

Result

Result Screenshot

Conclusion:

This is how you can write css in js and create reusable components with emotion css and how to pass props and based on props you can mutate your stylings.

There are lot of features and concepts in emotion you can create img wrappers and div,section wrappers. if you go below provided link you’ll know more about it.

For More Info

https://emotion.sh/docs/introduction

Thank you

Antstack Blog Post
Antstack Blog Post

Are you planning to go to serverless? AntStack is a cloud computing service and consulting company primarily focusing on Serverless Computing. We help companies get up and running with serverless, and we’ll make sure that there are no limits.

Keep track of our socials and connect with us - LinkedIn