Styled component 에서 Tailwind CSS 로
styled-components를 신봉자이던 내가 Tailwind로 넘어온 이유

프론트엔드 개발을 처음 제대로 시작했을 때, 나는 styled-components를 굉장히 좋아했다.
당시 React 생태계에서는 CSS-in-JS가 굉장히 인기 있었고, 특히 styled-components는 “현대적인 React 스타일링 방식”처럼 느껴졌다.
무엇보다 좋았던 건:
- CSS가 분리 된 깔끔해 보이는 JSX
- 컴포넌트 단위 스타일링
- props 기반 동적 스타일링
이었다.
// Button.tsx
<Button>
Click me!
</Button>
// Button.style.ts
const Button = styled.button`
padding: 8px 12px;
border-radius: 8px;
background: black;
color: white;
`;
당시의 나는 이렇게 CSS가 완전히 분리 된 코드가 굉장히 “잘 구조화된 코드” 라고 느꼈다.
반면에 Tailwind를 처음 봤을 때는 거부감이 있었다.
<button className="px-4 py-2 rounded-md bg-black text-white">
이걸 보고 처음 든 생각은:
“JSX가 너무 지저분한데?”
였다.
className 안에 수많은 클래스가 나열된 모습은 가독성을 해치는 것처럼 느껴졌고, 심지어 과거에 많이 사용되던 Bootstrap과 비슷해 보여, 한때 발전했던 프론트엔드 스타일링 방식이 다시 과거로 돌아가는 듯한 인상마저 받았다.
시간이 지나면서 생각이 바뀌기 시작했다.
프로젝트 규모가 커지고, 협업이 많아지고, 디자인 시스템과 성능을 신경 쓰기 시작하면서 조금씩 다른 문제들이 보였다.
“깔끔한 JSX”가 꼭 유지보수하기 좋은 건 아니었다
styled-components를 오래 사용하다 보면 이런 코드가 점점 많아진다.
const Container = styled.div``
const Wrapper = styled.div``
const Inner = styled.div``
const Content = styled.div``
처음에는 JSX가 깔끔해 보여서 좋다. 그런데 시간이 지날수록 다른 문제가 보이기 시작했다.
네이밍 비용
styled-components의 가장 큰 숨은 비용은 모든 스타일에 이름을 붙여야 한다는 것이다.
CSS로는 그냥 div 하나면 끝나는 영역도, styled-components에서는 반드시 컴포넌트 이름을 정해야 한다. 그런데 의미 있는 이름을 매번 짓는 건 생각보다 어렵다.
실제로 동료 개발자들과 “이거 이름 뭘로 지을까요…” 와 같은 간단한 고민을 자주 나누곤 했다.
컨텍스트 스위칭 비용
이름 문제와 별개로, 스타일을 수정할 때마다 시선이 여러 번 이동한다.
- JSX 확인
- styled component 정의 찾기
- 다시 스타일 코드로 이동
이 과정을 반복하게 된다.
반면 Tailwind는 스타일이 JSX 근처에 그대로 존재한다.
<button
className="
px-4 py-2
rounded-md
bg-black text-white
"
>
저장하기
</button>
처음에는 className이 길어 보여도, 익숙해지니 오히려 읽는 속도가 훨씬 빨랐다.
Tailwind 를 활용한 컴포넌트 패턴화
예전에는 Tailwind가 단순히 “className 덕지덕지 붙이는 방식”이라고 생각했다.
그런데 실제로 사용해보니 생각보다 훨씬 구조적이었다.
특히:
- clsx
- cva
- tailwind-variants
같은 도구와 함께 사용하면 컴포넌트 패턴화가 잘 된다.
const buttonVariants = cva(
"rounded-md px-4 py-2 font-medium",
{
variants: {
variant: {
primary: "bg-black text-white",
secondary: "bg-zinc-100 text-black",
},
},
}
);
type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
variant?: "primary" | "secondary";
};
function Button({ variant = "primary", className, ...props }: ButtonProps) {
return (
<button
className={cn(buttonVariants({ variant }), className)}
{...props}
/>
);
}
결국 중요한 건 “스타일을 어디에 적느냐” 보다, “얼마나 일관된 규칙으로 관리되느냐” 에 가까웠다.
런타임 이점

그 외의 이점들
shadcn/ui 와의 궁합
Tailwind를 쓰면서 가장 인상적이었던 건 shadcn/ui 같은 생태계의 등장이었다.
shadcn/ui 라이브러리는 버전에 종속되지 않고, 컴포넌트가 내 코드의 일부가 되므로, 자유롭게 수정할 수 있다.
Tailwind 클래스로 되어 있으니, 디자인 시스템에 맞춰 튜닝도 간편하다.
styled-components 기반 컴포넌트 라이브러리를 쓰면 “스타일을 override하는 방법” 을 매번 고민해야 했다. 하지만, Tailwind + shadcn 조합에서는 그냥 className을 바꾸면 끝이다.
훨씬 직관적이고 간편하게 커스터마이징이 가능해졌다.
AI와의 시너지
Tailwind는 LLM 챗봇 서비스로 다루기에 훨씬 적합한 형태다.
스타일이 마크업과 한 파일에 있으니, AI가 전체 컨텍스트를 한 번에 본다. 별도의 styled component 정의 파일을 찾아다닐 필요가 없다.
styled-components를 쓰는 프로젝트에서 AI에게 컴포넌트를 만들어 달라고 하면, 매번 네이밍 컨벤션이 들쭉날쭉하다. Wrapper인지 Container인지 Box인지. 반면 Tailwind는 그런 결정을 할 필요 자체가 없다.
Style 도구에 대한 생각
나는 여전히 styled-components가 잘못된 도구라고 생각하지 않는다. 동적 테마가 핵심인 프로젝트 혹은 이미 잘 굴러가고 있는 코드베이스라면 굳이 갈아엎을 이유가 없다.
다만 예전엔 “코드가 깔끔해 보이는가” 가 중요한 기준이었다면, 지금은 “수정할 때 얼마나 빨리 도달할 수 있는가”, “런타임 비용이 얼마나 드는가”, “팀과 AI가 같은 규칙 위에서 일할 수 있는가” 같은 것들을 더 보게 됐다.
마무리
styled-components를 쓰는 내내 네이밍, 컨텍스트 전환에 대한 불편함을 느끼고 있었음에도, 불편함에 대한 비용을 인식하지 못하고 있었다. 익숙한 방식이었기 때문에, 당연한 비용이라고 생각했다.
Tailwind를 공부하는 과정에서야 이를 비용으로 인식할 수 있었다. 앞으로 새 도구를 익힐 때 왜 이런 접근이 등장했고, 어떤 문제를 풀고 있는가 에 대해서 집중하는 자세를 가져야 할 것 같다.