현재 실무 프로젝트에서 emotion
을 사용하고 있는데,
기존의 styled components와 비슷해서 어려울 건 없지만 theme
세팅 방법에 대해 정리해두려 한다. (설치부터의 사용법은 다음에!)
npm install @emotion/react @emotion/styled
React 프로젝트에서 emotion을 사용할 수 있는 @emotion/react
패키지와 styled-components처럼 스타일링 컴포넌트 생성을 위한 @emotion/styled
를 설치해 준다.
emotion에서는 아래와 같이 테마에 포함될 스타일 속성들을 객체 형태로 정의할 수 있다.
// theme.ts
export const theme = {
fontSizes: {
sm: "13px",
base: "14px",
md: "18px",
},
lineHeight: {
sm: "13px",
base: "14px",
md: "18px ",
},
letterSpacing: "-2%",
colors: {
main: "#2F3438",
red: "#FF0000",
white: "#FFFFFF",
gray: "#999999",
blueGray2: "#505B6D",
blueGray3: "#505B6D",
blueGray4: "#9DA8B6",
border01: "#E7EDF6",
border02: "#8899B6",
bg01: "#F9FAFC",
},
};
theme.js
파일을 생성해서, fontSizes, lineHeight, letterSpacing, colors 등 필요에 따라 테마를 설정해 준다.
GlobalStyle css -> :root
세팅 방식인데, 비교해서 보니 emotion의 theme
설정이 조금 더 스타일을 세분화해서 사용할 수 있는 장점이 있는 것 같다. :root{
--main-color:#724FFF;
--font-color:#191919;
--sub-font-color:#767676;
--extra-font-color: #909090;
--tertiary-font-color: #575757;
--border-color:#DBDBDB;
--modal-border-color: #EDEDED;
--input-background-color:#F1F1F5;
--btn-border-color:#724FFF;
--btn-background-color:#724FFF;
--btn-point-color: #7D4FFF;
--playlist-info-bg-color: #8969FF;
--playlist-info-sub-color: #DBDBDB;
--error-color: #FF003E;
--font-xl : 22px;
--font-l: 18px;
--font-lg: 16px;
--font-md: 14px;
--font-sm : 12px;
letter-spacing: -0.02em;
}
이건 TypeScript를 사용한다면 emotion을 사용하기 좋은 큰 이유이자 이점이라고 생각한다.
TypeScript를 사용하는 경우, @emotion/react
모듈의 Theme
인터페이스를 확장하여 테마 객체에 정의된 속성들에 대한 타입을 선언 및 지정해 줄 수 있다(!)
/// theme.ts
import "@emotion/react";
declare module "@emotion/react" {
export interface Theme {
fontSizes: {
sm: string;
base: string;
md: string;
};
lineHeight: {
sm: string;
base: string;
md: string;
};
letterSpacing: string;
colors: {
wb500: string;
red: string;
white: string;
gray: string;
blueGray2: string;
blueGray3: string;
blueGray4: string;
border01: string;
border02: string;
bg0: string;
};
}
}
이렇게 테마를 정의한 theme.ts
파일 내에 Theme에 대한 타입을 함께 지정해 두면,
테마 내 스타일 속성을 사용할 때의 타입 체킹까지 가능하게 된다.
(물론 타입 선언이 theme 세팅에서의 필수가 아니라 세팅하지 않아도 작동에 문제는 없다.)
theme 타입 세팅 시 주의⚠️
declare
로 정의해 준다고 해서 타입 선언을 다른 파일에 분리해 정의를 하게 될 경우 Typescript compiler가 type을 감지하지 못하는 버그가 발생할 수 있다고 한다.Property 'colors' does not exist on type 'Theme'.
다음과 같은 에러를 만날 수 있으니 꼭 타입을 한 파일 같이 내에 넣어 줄 것!
(나도 작업 중 만난 에러인데, 해당 원인 외에도 theme 내에 설정한 스타일이 타입 내에 누락 될 경우에도 에러 문구를 만날 수 있으니 꼼꼼한 타입체킹하기)
// index.ts
import React from "react";
import ReactDOM from "react-dom/client";
import { ThemeProvider } from "@emotion/react";
import App from "./App";
import "./index.css";
import "./fonts/Font.css";
import { theme } from "./styles/theme";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
</React.StrictMode>
);
index.ts 파일에 theme.ts 파일을 불러온 다음, ThemeProvider로 App 컴포넌트를 감싸주면 세팅이 끝난다.
import styled from "@emotion/styled";
export const Wrapper = styled.div`
color: ${({ theme }) => theme.colors.main};
font-size : ${({ theme }) => theme.fontSizes.sm};
background-color : ${({ theme }) => theme.colors.bg};
`;
작업하게 될 컴포넌트 스타일 적용 시 다음과 같이 theme을 가져와 사용하면 된다.
ThemeProvider 덕분에 theme
을 import하는 등의 과정은 불필요하다!
emtion의 theme 세팅 및 사용 방법은 스타일 컴포넌트와 비슷한 방법으로,
emotion 하면 또 다른 가장 유명한 방법은 태그에서 css props로 스타일을 지정하고 접근할 수 있는 방법이 있다. 이 부분은 다음에 한 번더 포스팅으로 정리해 보고 싶다!