이 글에서는 Next.js 15버전 환경에서 MUI 테마를 적용하는 방법에 대해 스텝 바이 스텝 형식으로 설명한다.
문제 상황
Next.js 15 버전에서 MUI를 활용한 UI 개발 중 반복되는 UI 스타일링과 상속 중첩에 따른 가독성 저해 문제가 발생했다.
(쉽게 말하자면 일일히 UI 스타일링 하는 것과 다른 UI를 상속 받아 스타일링을 추가했을 때 부모 요소 스타일링을 추적하는 것이 지겨웠다.)
필자는 MUI 전역 스타일링(테마)을 활용하여 위 문제들을 해결하려 했지만 Next.js 환경 특성(서버 컴포넌트, 클라이언트 컴포넌트의 분리 등)에 따라 테마 적용에 어려움을 겪었다.
해결 방법
종속성 설치
npm install @mui/material-nextjs @emotion/cache
app/layout.tsx 수정
// AppRouterCacheProvider 임포트
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
// <body> 태그 내부의 모든 요소들을 <AppRouterCacheProvider>으로 랩핑한다.
<body>
<AppRouterCacheProvider>
{children}
</AppRouterCacheProvider>
</body>
app/layout.tsx 에 AppRouterCacheProvider 컴포넌트를 적용합니다.
전역 테마 파일 생성(app/styles/MuiTheme.ts)
import { createTheme } from '@mui/material/styles';
// MUI 테마 생성
const MuiTheme = createTheme({
components: {
// MUI의 TextField 컴포넌트에 대한 스타일 오버라이드
MuiTextField: { // MUI의 TextField 컴포넌트 지정
styleOverrides: { // MuiTextField의 내부 스타일을 덮어쓰기
root: { // MuiTextField의 최상위 DOM 요소를 대상으로 스타일을 적용
// 포커스 상태에서 입력 필드의 보더(border) 색상 변경
"& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline": {
borderColor: "var(--main-color)", // 포커스 상태의 보더 색상 (CSS 변수 사용)
},
},
},
},
},
});
export default MuiTheme;
위 테마 파일을 통해 MUI의 모든 TextField 컴포넌트에 해당 스타일이 적용됩니다.
전역 테마 컴포넌트 생성(app/components/ThemeRegistry.tsx)
"use client";
import { ThemeProvider } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import MuiTheme from "@/styles/MuiTheme";
export default function ThemeRegistry({
children,
}: {
children: React.ReactNode;
}) {
return (
<ThemeProvider theme={MuiTheme}>
<CssBaseline />
{children}
</ThemeProvider>
);
}
ThemeRegistry.tsx 컴포넌트는 MUI의 ThemeProvider 컴포넌트를 랩핑한 컴포넌트입니다.
layout.tsx에 ThemeProvider를 곧바로 적용하지 않고 ThemeRegistry.tsx 컴포넌트로 랩핑한 이유는 아래와 같습니다.
1. 서버 컴포넌트와 클라이언트 컴포넌트의 분리
Next.js의 App Router에서는 기본적으로 layout.tsx가 서버 컴포넌트로 동작합니다.
하지만 MUI의 ThemeProvider는 클라이언트에서만 동작해야 합니다.
따라서 ThemeRegistry.tsx를 use client로 선언해 클라이언트 전용 컴포넌트로 분리해야 합니다.
2. Emotion 캐시 처리 (SSR 스타일 동기화)
Next.js는 서버 사이드 렌더링(SSR)을 기본으로 합니다.
MUI의 Emotion 스타일을 서버와 클라이언트 간 동기화해야 합니다.
ThemeRegistry에서 Emotion 캐시(CacheProvider)를 함께 설정하면, 서버에서 생성된 스타일이 클라이언트로 제대로 전달되어 hydration mismatch 문제를 방지할 수 있습니다.
app/layout.tsx 수정
// AppRouterCacheProvider 임포트
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
// ThemeRegistry 임포트
import ThemeRegistry from "@/components/ThemeRegistry";
// <AppRouterCacheProvider>으로 랩핑된 요소를 <ThemeRegistry>로 중첩랩핑한다.
<body>
<AppRouterCacheProvider>
<ThemeRegistry>
{children}
</ThemeRegistry>
</AppRouterCacheProvider>
</body>
서버 재시작
npm run dev
결과
모든 TextField 컴포넌트에 테두리 스타일이 적용된 것을 확인할 수 있다.
참고자료
https://mui.com/material-ui/integrations/nextjs/
Next.js integration - Material UI
Learn how to use Material UI with Next.js.
mui.com
끝.
'프론트엔드 > Next.js' 카테고리의 다른 글
[Next.js] error.tsx와 useErrorHandler를 활용한 전역 에러 처리 (0) | 2024.12.17 |
---|---|
[Next.js] Next.js에서 styled-components 글로벌 스타일 적용 방법 (1) | 2024.12.17 |
[Next.js] "use client"는 CSR 방식과 동일할까? (1) | 2024.12.02 |
[Next.js] Next.js에서 SVG를 컴포넌트처럼 사용하는 방법 (0) | 2024.12.01 |
[Next.js] Next.js + Styled-components 적용하기 (0) | 2024.11.30 |