이번주는 디자인 토큰을 이용한 대표적인 공용 컴포넌트를 만들어보려고 한다.
디자인 토큰은 색상, 크기, 글꼴 등 디자인 변수를 저장하는데 사용하는 요소 단위이다.
예를 들어, 아래 코드는 color 에 관련된 디자인 토큰이다.
//색 관련 디자인 토큰
//메인컬러 라벤더
const MAIN = {
base: "#AC87C5", // 600 과 동일값
0: "#FFE5E5",
200: "#E0AED0",
400: "#B784B7",
600: "#AC87C5",
800: "#8E7AB5",
1000: "#756AB6",
};
const PALLETE = {
teal: {
base: "#709FB0",
light: "#A0C1B8",
},
green: {
base: "#C6DCBA",
light: "#D7E4C0",
weight: "#BBC3A4",
},
gray: {
base: "#C7C8CC",
light: "#E3E1D9",
weight: "#B4B4B8",
},
peach: {
base: "#EFB495",
light: "#EFD595",
weight: "#ffc0cb",
},
.....
디자인은 무한히 재사용될 수 있기때문에 이를 토큰화 하여 만들면 추후에 관리하기 편해진다.
그럼 "디자인 토큰만 정하면 되는거 아닌가?" 라는 의문이 들것이다.
간단한 프로젝트의 경우 디자인 토큰만 설정해서 개발자와 디자이너 모두 편리하게 사용할 수 있을거라 생각이 들겠지만 사실은 그렇지 않다. 프로젝트를 시작하는 초기에는 기업마다 만든 디자인 규칙이 잘 이행될 수 있으나 시간이 지나면서 규칙이 지켜지지 않는 경우가 많아진다.
이를 해결하기 위해 나온것이 바로 디자인 토큰을 이용한 디자인 시스템이다.
디자인 시스템이란 디자인 원칙, 재사용 가능한 UI 패턴/ 컴포넌트, 코드로 구성된 시스템을 이야기한다.
즉, 디자인 토큰이 적용된 상태에서 재사용 가능한 UI패턴과 컴포넌트를 코드로 구현하여 사용 가능한 상태로 만들어내는 것이다.
이러한 디자인 시스템을 활용하면 혼란을 방지하고 (팀 내 언어통일) 효율적인 작업을 할 수 있다.
그렇다면 디자인 토큰을 이용하여 테마를 설정하고 공용컴포넌트를 작성해보자.
여기서 테마란 디자인 시스템을 구축하는 모든 디자인 관련들을 말한다.
테마를 잘 정의하면 생산성이 증가하고 디자인 일관성이 생길것이다.
사실 개발자 입장에서 보면 button 이나 select 등 재사용할 수 있는 컴포넌트에 대해 디자인 토큰을 일일이 정하는 일은 드물거라고 생각한다.
그래서 나는 공용으로 재사용이 많이 되는 태그에 관해서 테마를 설정했다.
(먼저 color 와 size 디자인 토큰을 만들어둔 상태)
src -> styleTheme 폴더를 두어 button.style.js 파일을 만들었다.
어떤식으로 해야 개발자 입장에서 button을 골라쓸수 있을까 생각하다가 color 와 size로 나눌수 있을것같았다. 다양한 버튼이 필요한 프로젝트라는 가정하에 아래와 같이 테마를 설정하면 재사용하기 쉬울거같다.
//버튼 스타일 테마
import styled, { css } from "styled-components";
import { COLORS } from "../../designToken/color";
import { SIZES } from "../../designToken/size";
const ButtonColorCss = {
mainPurple: {
css: css`
background-color: ${COLORS.MAIN.base};
color: ${COLORS.SYSTEM.black};
`,
activeColor: css`
background-color: ${COLORS.MAIN[200]};
`,
},
teal: {
css: css`
background-color: ${COLORS.PALLETE.teal.base};
color: ${COLORS.SYSTEM.black};
`,
},
green: {
css: css`
background-color: ${COLORS.PALLETE.green.base};
color: ${COLORS.SYSTEM.black};
`,
},
};
const ButtonSizeCss = {
mini: {
css: css`
width: ${SIZES.BUTTON.mini.width};
height: ${SIZES.BUTTON.mini.height};
`,
},
small: {
css: css`
width: ${SIZES.BUTTON.small.width};
height: ${SIZES.BUTTON.small.height};
`,
},
medium: {
css: css`
width: ${SIZES.BUTTON.medium.width};
height: ${SIZES.BUTTON.medium.height};
`,
},
large: {
css: css`
width: ${SIZES.BUTTON.large.width};
height: ${SIZES.BUTTON.large.height};
`,
},
};
export const StyleBtn = styled.button`
border: none;
border-radius: 10px;
cursor: pointer;
${({ color }) => ButtonColorCss[color].css}
${({ size }) => ButtonSizeCss[size].css}
&:active {
background-color: ${({ color }) => ButtonColorCss[color].activeColor};
transform: scale(0.8);
}
`;
이렇게 button에관련하여 테마를 만들었다면 이제 공용컴포넌트를 만들어보자
//버튼 공용컴포넌트
import { StyleBtn } from "../styleTheme/button.style";
const Button = ({ color, size, text, ...restProps }) => {
return (
<StyleBtn size={size} color={color} {...restProps}>
{text}
</StyleBtn>
);
};
export default Button;
버튼 컴포넌트에서 color , size, text, restProps 를 props로 설정했다.
그리고 이 컴포넌트를 페이지네이션 컴포넌트에서 사용해보겠다.
//페이지네이션 컴포넌트
import { useSearchParams } from "react-router-dom";
import styled from "styled-components";
import Button from "./button";
function Pagination({ total, limit, currentPage, curParams, setCurParams }) {
const numPages = Math.ceil(total / limit);
const [searchParams, setSearchParams] = useSearchParams();
// + 일 때와, - 일 때
const handlePageChange = (page) => {
searchParams.set("currentPage", page);
setSearchParams(searchParams);
};
return (
<ButtonWrapper>
<Button color="lemon" size="mini" text="<<" />
<Button
color="peach"
size="mini"
text="<"
onClick={() => handlePageChange(currentPage - 1)}
disabled={currentPage === 1}
/>
{Array(numPages)
.fill()
.map((_, i) => (
<Button
color="peach"
size="mini"
text={i + 1}
key={i + 1}
onClick={() => handlePageChange(i + 1)}
/>
))}
<Button
color="peach"
size="mini"
text=" >"
onClick={() => handlePageChange(currentPage + 1)}
disabled={currentPage === numPages}
/>
<Button color="lemon" size="mini" text=">>" />
</ButtonWrapper>
);
}
const ButtonWrapper = styled.div`
gap: 5px;
display: flex;
justify-content: center;
align-items: center;
`;
// const SButton = styled.button`
// border: none;
// border-radius: 8px;
// padding: 10px;
// margin: 0;
// background: #ffc0cb;
// color: black;
// font-size: 1rem;
// &:hover {
// background: tomato;
// cursor: pointer;
// }
// `;
export default Pagination;
이와같이 적용했는데, 디자인시스템을 설정하지 않았다면 아래 (주석된것)과 같이 작성해야했을것이다. 확실히 코드가 간결해졌다.

해당코드는 사진과 같이 나타난다.
끝..!
다음 글은 이런 공용컴포넌트를 StoryBook 으로 관리하는 방법으로 돌아올 예정이다!