7 min read Oct 14, 2021 How to Style an app using Emotion CSS in JS
Surendra Reddy S

7 min read

2021-10-14

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.jpg

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

Topics

Share this blog

How to Style an app using Emotion CSS in JS

Oct 14, 2021

Writing css in js by using emotion.js

7 min read

Oct 14, 2021

This website stores cookies on your computer.

These cookies are used to collect information about how you interact with this website and allow us to remember you. We use this information in order to improve and customize your browsing experience and for analytics and metrics about our visitors on this website.

If you decline, your information won’t be tracked when you visit this website. A single cookie will be used in your browser to remember your preference not to be tracked.