이 글은 next.js 15와 styled-components를 사용한 프로젝트에 대해 다룹니다.
이 글의 테마는 MUI의 디자인 시스템 컬러를 참고하였습니다.

 

0. 코드 템플릿

테마 적용 코드 템플릿.zip
0.00MB

 

1. 테마 타입 정의

src/types/styled.d.ts
import "styled-components";

declare module "styled-components" {
  export interface DefaultTheme {
    colors: {
      primary: {
        light: string;
        main: string;
        dark: string;
      };
      secondary: {
        light: string;
        main: string;
        dark: string;
      };
      info: {
        light: string;
        main: string;
        dark: string;
      };
      success: {
        light: string;
        main: string;
        dark: string;
      };
      warning: {
        light: string;
        main: string;
        dark: string;
      };
      error: {
        light: string;
        main: string;
        dark: string;
      };
    };
  }
}

 

2. 테마 생성

src/styles/theme.ts
import { DefaultTheme } from "styled-components";

export const theme: DefaultTheme = {
  colors: {
    primary: {
      light: "#42A5F5",
      main: "#2196F3",
      dark: "#1E88E5",
    },
    secondary: {
      main: "#BA68C8",
      light: "#9C27B0",
      dark: "#7B1FA2",
    },
    info: {
      main: "#01579B",
      light: "#0288D1",
      dark: "#03A9F4",
    },
    success: {
      main: "#4CAF50",
      light: "#2E7D32",
      dark: "#1B5E20",
    },
    warning: {
      main: "#FF9800",
      light: "#E65100",
      dark: "#EF6C00",
    },
    error: {
      main: "#EF5350",
      light: "#D32F2F",
      dark: "#C62828",
    },
  },
};

 

3. 테마 프로바이더 생성

src/components/ThemeProviderWrapper.tsx
"use client";

import { ThemeProvider } from "styled-components";
import { theme } from "@/styles/theme";

const ThemeProviderWrapper = ({ children }: { children: React.ReactNode }) => {
  return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
};

export default ThemeProviderWrapper;

 
 

4. 테마 프로바이더 적용

src/app/layout.tsx
import Sidebar from "@/components/ui/sidebar/Sidebar";
import SidebarButton from "@/components/ui/sidebar/SidebarButton";
import ThemeProviderWrapper from "@/components/ThemeProviderWrapper"; // 수정 부분✨
import type { Metadata } from "next";

export const metadata: Metadata = {
  title: "데브카드(DevCard) | 개발자 면접 준비를 위한 면접질문 카드",
  description: "데브카드는 개발자 면접 준비를 위한 면접질문 카드를 제공합니다.",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="ko">
      <body>
        // 수정 부분✨
        <ThemeProviderWrapper>
          <Sidebar />
          <SidebarButton />
          {children}
        </ThemeProviderWrapper>
        // 수정 부분✨
      </body>
    </html>
  );
}

 
 

5. 타입스크립트 설정

tsconfig.json
{
  "compilerOptions": {
	...기존 코드,
    "types": ["styled-components"]
  },
}

 

6. 서버 재시작

$ npm run dev


Q1. 왜 테마 프로바이더에 MUI 테마를 삽입한 후 styled.div에서 테마를 사용할 수 없는 이유에 대해 아주 자세히 설명해봐

A1.
문제 상황

MUI의 ThemeProvider로 테마를 설정했음에도 불구하고, styled-components에서 MUI 테마에 접근할 수 없는 이유는 두 라이브러리의 테마 시스템이 독립적이기 때문입니다.


---

1. MUI와 styled-components의 테마 시스템 차이

MUI의 테마 시스템

MUI는 자체적으로 React Context를 사용해 테마를 관리합니다.

@mui/material/styles의 ThemeProvider가 MUI 컴포넌트에서 테마 값을 공유합니다.

MUI 컴포넌트(Button, Typography 등)에서는 내부적으로 이 테마를 참조해서 스타일이 적용됩니다.


import { ThemeProvider, createTheme } from '@mui/material/styles';

const theme = createTheme({
  palette: {
    primary: {
      main: '#1976d2',
    },
  },
});

중요 포인트

MUI 컴포넌트 내부에서는 이 테마에 자동으로 접근 가능.

하지만 styled-components는 이 컨텍스트에 접근할 방법이 없습니다.



---

styled-components의 테마 시스템

styled-components도 자체적으로 React Context를 사용해 테마를 관리합니다.

ThemeProvider로 테마를 주입하고, 이 값을 props.theme로 전달합니다.


import { ThemeProvider } from 'styled-components';

const theme = {
  colors: {
    primary: '#1976d2',
  },
};

중요 포인트

styled-components는 오직 자체 컨텍스트에서 전달된 테마만 사용합니다.

MUI의 테마 컨텍스트에 접근할 수 없습니다.



---

2. 왜 MUI 테마가 styled-components에 전달되지 않을까?

독립된 컨텍스트 사용:
MUI와 styled-components는 서로 다른 Context API 인스턴스를 사용합니다.
→ 따라서 MUI의 테마는 styled-components 컴포넌트에 자동으로 전달되지 않습니다.

자동 전달이 안 됨:
두 라이브러리가 서로 다른 테마 객체 구조를 사용하기 때문에, React는 MUI의 테마를 styled-components의 theme prop에 자동으로 전달하지 않습니다.



---

3. 해결 방법: 두 테마 시스템 통합하기

방법 1️⃣ MUI 테마를 styled-components에도 전달

MUI ThemeProvider와 styled-components ThemeProvider를 중첩해서 MUI 테마를 두 곳 모두에 전달해야 합니다.

import { ThemeProvider as MuiThemeProvider, createTheme } from '@mui/material/styles';
import { ThemeProvider as StyledThemeProvider } from 'styled-components';

const theme = createTheme({
  palette: {
    primary: {
      main: '#1976d2',
    },
  },
});

function App() {
  return (
    <MuiThemeProvider theme={theme}>
      <StyledThemeProvider theme={theme}>
        <MyComponent />
      </StyledThemeProvider>
    </MuiThemeProvider>
  );
}

이렇게 하면:

MUI 컴포넌트는 MUI의 ThemeProvider에서 테마 값을 받습니다.

styled-components는 StyledThemeProvider를 통해 동일한 테마 값을 받습니다.


> ✅ 결과: 두 테마 시스템이 동일한 테마 값을 공유하게 됩니다.




---

방법 2️⃣ useTheme 훅을 사용해 수동으로 전달

MUI의 useTheme() 훅을 사용해 테마를 가져와 직접 넘겨줄 수도 있습니다.

import styled from 'styled-components';
import { useTheme } from '@mui/material/styles';

const StyledDiv = styled.div`
  background-color: ${({ theme }) => theme.palette.primary.main};
`;

const MyComponent = () => {
  const muiTheme = useTheme();

  return <StyledDiv theme={muiTheme}>테마 적용</StyledDiv>;
};

이렇게 하면:

MUI의 테마를 직접 props로 전달해 styled-components가 이를 사용할 수 있습니다.

다만, 매번 테마를 직접 전달해야 하기 때문에 코드가 반복될 수 있습니다.



---

4. 정리

핵심 이유:
MUI와 styled-components는 서로 다른 Context 시스템을 사용하기 때문에, MUI 테마가 자동으로 styled-components에 전달되지 않습니다. 이를 해결하기 위해서는 두 테마 시스템을 명시적으로 연결해야 합니다.



Q2. 아 그럼 styled()로 선언하는 컴포넌트는 MUI 문법이야?

A2. 네, 맞습니다. styled() 함수는 MUI에서 제공하는 스타일링 유틸리티입니다.

MUI의 styled()는 @mui/system에서 제공되며, MUI 테마와 깊게 통합되어 있어 styled-components와는 다른 방식으로 동작합니다.


---

🔍 차이점: MUI의 styled() vs. styled-components


---

✅ MUI의 styled() 사용 예시

import { styled } from '@mui/system';

const MyStyledDiv = styled('div')(({ theme }) => ({
  backgroundColor: theme.palette.primary.main,
  color: theme.palette.secondary.contrastText,
  padding: theme.spacing(2),
  borderRadius: '8px',
}));

const MyComponent = () => {
  return <MyStyledDiv> MUI 테마가 적용된 div </MyStyledDiv>;
};

특징:

theme 객체가 자동으로 주입됨 (별도로 전달 필요 없음)

MUI 테마에 맞춰 스타일이 동적으로 적용됨

MUI 컴포넌트와 호환성이 뛰어남



---

✅ styled-components의 styled() 사용 예시

import styled from 'styled-components';

const MyStyledDiv = styled.div`
  background-color: ${({ theme }) => theme.colors.primary};
  color: ${({ theme }) => theme.colors.secondary};
  padding: 16px;
  border-radius: 8px;
`;

특징:

테마 값을 사용하려면 별도로 **ThemeProvider**로 테마 주입이 필요

MUI 테마와의 통합이 자동으로 이루어지지 않음

더 범용적으로 사용 가능 (MUI에 종속되지 않음)



---

🎯 언제 MUI의 styled()를 사용해야 할까?

프로젝트에서 MUI 컴포넌트를 주로 사용하는 경우

MUI 테마 설정에 맞춰 스타일링을 일관되게 유지하고 싶은 경우

MUI의 시스템 속성(예: spacing, palette)을 그대로 활용하고 싶을 때


🎯 언제 styled-components를 사용해야 할까?

MUI 외에 다른 스타일링 접근법이 필요한 경우

MUI와 무관한 커스텀 스타일링이 필요한 경우

라이브러리 종속성이 적은 범용적인 스타일을 작성할 때



---

🔥 정리

styled() → MUI 문법

styled-components의 styled와 유사하지만, MUI 테마와 자동으로 통합

MUI 컴포넌트 스타일링 시에는 @mui/system의 styled()를 사용하는 것이 더 효율적