React Conf 2024 - Key Announcements and Takeaways
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
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