웹 개발자에게 완벽한 UI 툴킷을 찾는 것은 끊임없는 노력입니다. 수년 동안 React 개발자들은 Material-UI (MUI), Ant Design, Chakra UI와 같은 전통적인 컴포넌트 라이브러리에 의존해 왔습니다. 이러한 라이브러리는 풍부한 사전 구축 컴포넌트를 제공하여 개발 속도를 높여줄 것을 약속합니다. 하지만 종종 제어력 부족, 스타일 오버라이드 시 발생하는 어려움, 그리고 번들 크기 증가라는 단점을 수반합니다.
여기 Shadcn UI가 등장했습니다. React 커뮤니티를 강타한 패러다임 전환적인 접근 방식입니다. 여러분이 익숙한 방식의 컴포넌트 라이브러리가 아닙니다. 그보다 더 나은 것입니다. 아름답게 디자인되고 접근성이 뛰어나며 끝없이 재사용 가능한 컴포넌트 모음으로, npm에서 종속성으로 설치하는 것이 아니라 프로젝트에 직접 복사해서 사용합니다.
이 포괄적인 4000단어 튜토리얼은 여러분을 완전한 초보자에서 자신감 있는 Shadcn UI 실무자로 안내하는 확실한 가이드가 될 것입니다. 우리는 그 근본 철학을 탐구하고, 상세한 설정 과정을 거치며, 복잡한 UI를 구축하고, 고급 테마 및 폼 핸들링을 마스터하며, 대규모 애플리케이션을 위한 모범 사례를 논의할 것입니다. UI 툴킷에 대해 기대하는 바를 다시 생각할 준비를 하십시오.
개발 팀이 최대 생산성으로 함께 작업할 수 있는 통합된 올인원 플랫폼을 원하십니까?
Apidog는 여러분의 모든 요구 사항을 충족하며, Postman을 훨씬 저렴한 가격으로 대체합니다!
Shadcn UI 철학 - 새로운 구축 방식
코드를 한 줄도 작성하기 전에 Shadcn UI가 왜 존재하고 어떤 문제를 해결하는지 이해하는 것이 가장 중요합니다. 이 핵심 철학을 파악하는 것이 그 잠재력을 완전히 발휘하는 열쇠입니다.
Shadcn UI가 아닌 것
- 전통적인 npm 패키지가 아닙니다.
package.json의 종속성 목록에서shadcn-ui를 찾을 수 없습니다. 이것이 가장 중요한 차이점입니다. - 모놀리식 라이브러리가 아닙니다. 버튼과 입력 필드만 필요한데 수백 개의 컴포넌트를 설치하도록 강요하지 않습니다.
- 제한적이지 않습니다. 특정 디자인 미학에 갇히거나 라이브러리 유지보수자가 제공하는 테마 기능에 제한되지 않습니다.
Shadcn UI인 것
- 재사용 가능한 코드 모음: 전문가가 엄선한 레시피 세트라고 생각하십시오. 원하는 레시피(예:
Card컴포넌트)를 선택하면, 자신의 주방(프로젝트)에서 요리할 수 있도록 지침(코드)이 제공됩니다. - 코드 소유권에 대한 약속: Shadcn 컴포넌트를 추가하면 해당 소스 코드(
.tsx파일)가 일반적으로components/ui/아래에 있는 코드베이스에 직접 배치됩니다. 이제 그것은 여러분의 컴포넌트입니다. 구조, 스타일, 로직 등 무엇이든 변경할 수 있습니다. 이는 간단한 시각적 조정을 위해!importantCSS 오버라이드나 복잡한 prop API와 씨름하는 답답한 경험을 없애줍니다. - 현대적이고 견고한 기반 위에 구축: Shadcn UI는 바퀴를 재발명하지 않습니다. 거인의 어깨 위에 서 있습니다.
- Tailwind CSS: 마크업에서 직접 어떤 디자인이든 생성하기 위한 저수준 빌딩 블록을 제공하는 유틸리티 우선 CSS 프레임워크입니다. Shadcn 컴포넌트는 Tailwind로만 스타일이 지정되어 있어, 이 프레임워크에 익숙하다면 놀라울 정도로 쉽게 사용자 정의할 수 있습니다.
- Radix UI: 스타일이 지정되지 않은 접근성 있는 저수준 UI 프리미티브 라이브러리입니다. Radix는 키보드 탐색, 포커스 관리, 접근성을 위한 ARIA 속성(a11y) 등 UI 컴포넌트의 복잡하고 종종 간과되는 모든 측면을 처리합니다. Shadcn은 이러한 강력한 헤드리스 프리미티브를 가져와 Tailwind CSS로 아름다운 스타일을 추가합니다.
이 모델의 주요 장점은 속도와 제어력의 융합입니다. 사전 구축된 컴포넌트를 사용하여 초기 속도를 얻으면서도 코드 소유에서 오는 장기적인 유연성과 유지보수성을 희생하지 않습니다.
무대 설정 - 프로젝트 설정 및 설치
이론에서 실습으로 전환해 봅시다. 처음부터 새 프로젝트를 설정할 것입니다. 이 가이드에서는 주로 Next.js를 사용할 것입니다. 서버 컴포넌트와 파일 기반 라우팅이 Shadcn UI의 정신과 완벽하게 일치하기 때문입니다. Vite 설정도 간략하게 다룰 것입니다.
1단계: 환경 필수 조건
개발 환경이 준비되었는지 확인하십시오. 다음이 필요합니다.
- Node.js: 최신 LTS(Long-Term Support) 버전을 권장합니다. 공식 Node.js 웹사이트에서 다운로드할 수 있습니다.
- 패키지 관리자: 이 튜토리얼에서는 Node.js에 번들로 제공되는
npm을 사용할 것입니다.yarn또는pnpm도 사용할 수 있습니다.
2단계: 새 Next.js 애플리케이션 생성
터미널을 열고 다음 명령을 실행하여 새 Next.js 프로젝트를 부트스트랩합니다.Bash
npx create-next-app@latest my-pro-shadcn-app --typescript --tailwind --eslint
이 명령은 my-pro-shadcn-app이라는 디렉토리에 새 애플리케이션을 스캐폴딩합니다. 몇 가지 중요한 플래그를 포함했습니다.
--typescript: Shadcn UI는 TypeScript로 작성되었으며 TypeScript 환경에서 가장 잘 작동합니다.--tailwind: Tailwind CSS는 Shadcn UI 스타일링의 필수 종속성입니다.--eslint: 코드 품질 유지를 위한 좋은 습관입니다.
설치 프로그램이 몇 가지 질문을 할 것입니다. 다음은 최신 Next.js 14+ 설정에 권장되는 선택 사항입니다.
✔ `src/` 디렉토리를 사용하시겠습니까? … No / **Yes**
✔ App Router를 사용하시겠습니까? (권장) … No / **Yes**
✔ 기본 가져오기 별칭을 사용자 정의하시겠습니까? … **No** / Yes
App Router를 사용하는 것은 표준 관행이며, src/ 디렉토리는 코드 구성에 도움이 됩니다. 완료되면 새 프로젝트로 이동하십시오.Bash
cd my-pro-shadcn-app
3단계: init 명령 - Shadcn UI 활성화
이것이 가장 중요한 단계입니다. Shadcn UI는 프로젝트를 구성하기 위한 CLI 도구를 제공합니다. 프로젝트의 루트 디렉토리에서 다음 명령을 실행하십시오.Bash
npx shadcn-ui@latest init
이렇게 하면 프로젝트 설정을 위한 대화형 설문이 시작됩니다. 각 질문과 그 중요성을 살펴보겠습니다.
- TypeScript를 사용하시겠습니까 (권장)?
Yes. 우리는 TypeScript 프로젝트에 있습니다. - 어떤 스타일을 사용하시겠습니까?
Defaultvs.New York. 두 가지 미리 정의된 시각적 스타일입니다.Default는 약간 더 넓고,New York은 더 간결합니다. Shadcn UI 웹사이트에서 예시를 볼 수 있습니다. 여기서는Default를 선택하겠습니다. - 기본 색상으로 어떤 색상을 사용하시겠습니까? 이는 UI의 기본 색상 팔레트를 설정합니다. 기본값은
Slate입니다. 지금은Slate를 그대로 사용하겠습니다. 나중에 변경하는 방법을 배울 것입니다. global.css파일은 어디에 있습니까? CLI는src/app/globals.css에서 이를 올바르게 감지합니다. 이 파일은 테마 설정을 위한 핵심 CSS 변수가 주입될 곳입니다.- 테마 설정을 위해 CSS 변수를 사용하시겠습니까?
Yes. 이는 Shadcn 테마 시스템의 핵심이며, 동적 변경(예: 다크/라이트 모드)과 쉬운 사용자 정의를 가능하게 합니다. tailwind.config.ts는 어디에 위치합니까? CLI는src/tailwind.config.ts를 감지합니다. 이 파일은 Shadcn의 테마 프리셋을 통합하기 위해 수정될 것입니다.- 컴포넌트 가져오기 별칭을 구성하십시오:
@/components. 이것은 모범 사례입니다. 파일이 아무리 깊게 중첩되어 있더라도import { Button } from "@/components/ui/button";와 같이 깔끔한 경로로 컴포넌트를 항상 가져올 수 있음을 의미합니다. - 유틸리티 가져오기 별칭을 구성하십시오:
@/lib/utils. 위와 마찬가지로 유틸리티 함수에 대한 것입니다. - React Server Components를 사용하고 있습니까?
Yes. 우리는 기본적으로 Server Components를 사용하는 App Router를 선택했습니다. components.json에 구성을 작성하시겠습니까?Yes. 이는 모든 선택 사항을 기억하는 중요한 파일을 생성하여npx shadcn-ui@latest add ...를 실행할 때마다 이러한 질문에 답할 필요가 없도록 합니다.
확인 후 CLI는 마법을 부립니다.
- 종속성 설치:
tailwindcss-animate및class-variance-authority와 같은 필요한 패키지를 추가합니다. components.json생성: 구성 선택 사항을 저장합니다.tailwind.config.ts업데이트: Shadcn UI 플러그인 및 테마 구성이 주입됩니다.globals.css업데이트: 전체 색상 팔레트, 테두리 반경 등을 정의하는 큰 CSS 변수 블록이 추가됩니다.lib/utils.ts생성: 이 파일은 Tailwind CSS 클래스를 조건부로 병합하기 위한 영리한 유틸리티인cn헬퍼 함수를 내보냅니다.
이제 프로젝트가 완전히 구성되었습니다.
(대안: Vite 설정)
Vite와 React를 사용하고 있다면 과정은 매우 유사합니다. Vite + React + TS 프로젝트를 설정한 후 Tailwind CSS를 수동으로 설치하고 npx shadcn-ui@latest init을 실행합니다. CLI는 Vite 설정을 감지할 만큼 똑똑하며 파일 위치(예: globals.css 대신 index.css)에 대해 약간 다른 질문을 할 것입니다.
UI 구축 - 간단한 컴포넌트에서 복잡한 레이아웃까지
설정이 완료되었으니 이제 구축을 시작해 봅시다. 핵심 워크플로우는 다음과 같습니다. 필요를 식별하고, 컴포넌트를 추가하고, 사용합니다.
4단계: 첫 번째 컴포넌트 추가 및 사용
기본 Next.js 보일러플레이트를 정리하고 간단한 인터페이스를 구축해 봅시다.
1. 버튼 추가:Bash
npx shadcn-ui@latest add button
어떤 일이 발생하는지 살펴보십시오. 새 파일 src/components/ui/button.tsx가 생성됩니다. 이것이 여러분의 버튼입니다. 여러분이 소유합니다.
2. 카드 추가:Bash
npx shadcn-ui@latest add card
이 명령은 더 흥미롭습니다. src/components/ui/card.tsx를 생성합니다. 이 파일을 검사하면 여러 컴포넌트를 내보내는 것을 볼 수 있습니다. Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter. 이는 복합 컴포넌트의 일반적인 패턴입니다.
3. UI 구축:
이제 src/app/page.tsx를 열고 내용을 다음으로 바꿉니다.TypeScript
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input"; // 다음으로 추가할 것입니다.
import { Label } from "@/components/ui/label"; // 그리고 이것도
export default function Home() {
return (
<main className="flex min-h-screen items-center justify-center bg-background p-8">
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle className="text-2xl">프로젝트 생성</CardTitle>
<CardDescription>
한 번의 클릭으로 새 프로젝트를 배포하세요.
</CardDescription>
</CardHeader>
<CardContent className="grid gap-4">
<div className="grid gap-2">
<Label htmlFor="name">이름</Label>
<Input id="name" placeholder="프로젝트 이름" />
</div>
<div className="grid gap-2">
<Label htmlFor="framework">프레임워크</Label>
{/* 나중에 Select 컴포넌트로 바꿀 것입니다. */}
<Input id="framework" placeholder="예: Next.js" />
</div>
</CardContent>
<CardFooter>
<Button className="w-full">배포</Button>
</CardFooter>
</Card>
</main>
);
}
Input 및 Label 컴포넌트가 없으므로 코드가 아직 실행되지 않습니다. 추가해 봅시다.Bash
npx shadcn-ui@latest add input
npx shadcn-ui@latest add label
이제 개발 서버를 실행합니다.Bash
npm run dev
http://localhost:3000으로 이동하십시오. 카드 안에 깔끔하고 전문적인 모양의 양식이 표시됩니다. w-full, max-w-md, grid와 같은 유틸리티 클래스를 JSX에 직접 사용하여 레이아웃을 제어하는 방식을 주목하십시오. 이것이 Shadcn과 Tailwind CSS를 결합하는 힘입니다.
5단계: 더 정교한 컴포넌트 소개
정적 입력은 좋지만 실제 앱에는 대화형 요소가 필요합니다. 양식을 개선해 봅시다.
1. Select 컴포넌트 추가: "프레임워크" 입력은 드롭다운이어야 합니다. Select 컴포넌트를 추가해 봅시다. 이것은 더 복잡하며 다른 컴포넌트에 종속성이 있습니다.Bash
npx shadcn-ui@latest add select
CLI는 똑똑합니다. Select가 작동하려면 Popover 컴포넌트가 필요하다는 것을 감지하고 해당 종속성도 설치할 권한을 요청할 것입니다. 이는 종속성을 수동으로 추적할 필요가 없도록 하는 환상적인 기능입니다.
2. Select 컴포넌트 통합: src/app/page.tsx에서 "프레임워크"에 대한 Input을 새 Select 컴포넌트로 바꿉니다.TypeScript
// 상단에 다음 import를 추가합니다.
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
// ... CardContent 내부
<div className="grid gap-2">
<Label htmlFor="framework">프레임워크</Label>
<Select>
<SelectTrigger id="framework">
<SelectValue placeholder="프레임워크 선택" />
</SelectTrigger>
<SelectContent>
<SelectItem value="nextjs">Next.js</SelectItem>
<SelectItem value="sveltekit">SvelteKit</SelectItem>
<SelectItem value="astro">Astro</SelectItem>
<SelectItem value="nuxt">Nuxt.js</SelectItem>
</SelectContent>
</Select>
</div>
브라우저를 새로 고치십시오. 이제 애니메이션과 적절한 키보드 탐색 기능을 갖춘 완벽하게 기능하고 접근성 있는 선택 드롭다운이 있습니다. 이 모든 것은 내부적으로 작동하는 Radix UI 덕분입니다.
3. Toast로 사용자 피드백 추가: 사용자가 "배포"를 클릭하면 어떻게 될까요? 피드백을 제공해야 합니다. Toast 컴포넌트가 이에 완벽합니다.
먼저 추가하십시오.Bash
npx shadcn-ui@latest add toast
다음으로, 토스트를 사용하려면 앱의 어느 곳에서든 표시될 수 있도록 루트 레이아웃에 <Toaster /> 컴포넌트를 추가해야 합니다. src/app/layout.tsx를 열고 수정하십시오.TypeScript
import { Toaster } from "@/components/ui/toaster" // Toaster import
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Toaster /> {/* 여기에 추가, body 닫기 바로 전 */}
</body>
</html>
)
}
이제 토스트를 트리거할 방법이 필요합니다. useToast 훅을 사용할 것입니다. src/app/page.tsx를 클라이언트 컴포넌트로 만들고 버튼 클릭을 처리하도록 업데이트해 봅시다.TypeScript
'use client'; // <-- 파일 맨 위에 추가
// ... 다른 import
import { useToast } from "@/components/ui/use-toast";
export default function Home() {
const { toast } = useToast(); // 훅에서 toast 함수 가져오기
function handleDeploy() {
toast({
title: "배포 예약 완료!",
description: "프로젝트 '프로젝트 이름'이 배포 중입니다.",
duration: 5000,
});
}
return (
<main className="flex min-h-screen items-center justify-center bg-background p-8">
<Card className="w-full max-w-md">
{/* ... CardHeader 및 CardContent ... */}
<CardFooter>
<Button className="w-full" onClick={handleDeploy}> {/* onClick 핸들러 추가 */}
배포
</Button>
</CardFooter>
</Card>
</main>
);
}
이제 "배포" 버튼을 클릭하면 화면 모서리에 세련된 알림이 나타납니다.
유효성 검사를 통한 전문적인 양식 구축
대부분의 실제 애플리케이션은 클라이언트 측 유효성 검사를 포함한 강력한 양식 처리가 필요합니다. Shadcn UI로 이를 처리하는 공식적인 방법은 상태 관리를 위해 react-hook-form과 스키마 유효성 검사를 위해 zod를 결합하는 것입니다. 구축해 봅시다.
6단계: 양식 종속성 설치
먼저 필요한 라이브러리를 설치해 봅시다.Bash
npm install react-hook-form zod @hookform/resolvers
react-hook-form: 성능이 뛰어나고 유연하며 확장 가능한 양식 라이브러리입니다.zod: TypeScript 우선 스키마 선언 및 유효성 검사 라이브러리입니다.@hookform/resolvers:react-hook-form이 유효성 검사를 위해zod를 사용할 수 있도록 하는 브리지 라이브러리입니다.
7단계: Shadcn Form 컴포넌트 추가
Shadcn UI는 react-hook-form을 UI 컴포넌트와 원활하게 연결하는 래퍼 역할을 하는 특수 Form 컴포넌트를 제공합니다.Bash
npx shadcn-ui@latest add form
이렇게 하면 src/components/ui/form.tsx가 추가됩니다. 이 파일은 컨텍스트 인식 컴포넌트 세트(Form, FormField, FormItem, FormLabel, FormControl, FormDescription, FormMessage)를 제공하여 보일러플레이트를 대폭 줄입니다.
8단계: 유효성 검사 스키마 생성
src/app/page.tsx에서 zod를 사용하여 양식 데이터의 모양과 규칙을 정의해 봅시다.TypeScript
// 상단에 다음 import를 추가합니다.
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
이제 Home 컴포넌트 바로 위에 스키마를 생성해 봅시다.TypeScript
const formSchema = z.object({
projectName: z.string().min(2, {
message: "프로젝트 이름은 최소 2자 이상이어야 합니다.",
}).max(50, {
message: "프로젝트 이름은 50자를 초과할 수 없습니다.",
}),
framework: z.string({
required_error: "표시할 프레임워크를 선택하십시오.",
}),
});
이 스키마는 두 필드를 정의합니다. projectName은 2자에서 50자 사이의 문자열이어야 하며, framework는 필수 문자열입니다.
9단계: 양식 연결
이제 이러한 새로운 도구를 모두 사용하도록 Home 컴포넌트를 리팩토링해 봅시다.TypeScript
export default function Home() {
const { toast } = useToast();
// 1. 양식을 정의합니다.
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
projectName: "",
},
});
// 2. 제출 핸들러를 정의합니다.
function onSubmit(values: z.infer<typeof formSchema>) {
// 양식 값으로 무언가를 합니다.
// ✅ 이것은 타입 안전하고 유효성이 검사됩니다.
console.log(values);
toast({
title: "다음 값을 제출했습니다:",
description: (
<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
<code className="text-white">{JSON.stringify(values, null, 2)}</code>
</pre>
),
});
}
// 3. Shadcn의 Form 컴포넌트로 JSX를 구축합니다.
return (
<main className="flex min-h-screen items-center justify-center bg-background p-8">
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle className="text-2xl">프로젝트 생성</CardTitle>
<CardDescription>
한 번의 클릭으로 새 프로젝트를 배포하세요.
</CardDescription>
</CardHeader>
<CardContent>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="projectName"
render={({ field }) => (
<FormItem>
<FormLabel>이름</FormLabel>
<FormControl>
<Input placeholder="프로젝트 이름" {...field} />
</FormControl>
<FormDescription>
이것은 공개 표시 이름입니다.
</FormDescription>
<FormMessage /> {/* 유효성 검사 오류 표시 */}
</FormItem>
)}
/>
<FormField
control={form.control}
name="framework"
render={({ field }) => (
<FormItem>
<FormLabel>프레임워크</FormLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="프레임워크 선택" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="nextjs">Next.js</SelectItem>
<SelectItem value="sveltekit">SvelteKit</SelectItem>
<SelectItem value="astro">Astro</SelectItem>
<SelectItem value="nuxt">Nuxt.js</SelectItem>
</SelectContent>
</Select>
<FormDescription>
배포하려는 프레임워크입니다.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" className="w-full">배포</Button>
</form>
</Form>
</CardContent>
</Card>
</main>
);
}
이것은 상당한 양의 코드이지만, 믿을 수 없을 정도로 강력하고 확장 가능한 패턴입니다. FormField 컴포넌트는 모든 상태 연결을 처리하며, FormMessage는 사용자가 필드와 상호 작용할 때 zod 스키마에서 올바른 유효성 검사 오류를 자동으로 표시합니다. 빈 프로젝트 이름으로 양식을 제출하여 유효성 검사가 작동하는 것을 확인해 보십시오.
테마 및 사용자 정의 마스터하기
Shadcn UI의 진정한 힘은 자신만의 것으로 만들기 시작할 때 발휘됩니다.
10단계: CSS 변수를 사용한 고급 테마 설정
전체 테마는 src/app/globals.css의 CSS 변수에 의해 정의됩니다. 이 파일을 열고 :root 및 .dark 블록을 찾으십시오.CSS
/* globals.css 예시 */
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
/* ... 그리고 더 많은 것 */
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
/* ... */
}
- 색상 변경: 값은
hsl()래퍼 없이 HSL(색조, 채도, 밝기) 값으로 표현됩니다. 이는 더 쉬운 조작을 위한 의도적인 선택입니다. 기본 브랜드 색상을 변경하려면 해당 색상의 HSL 값을 찾아--primary및--primary-foreground변수를 업데이트하기만 하면 됩니다. Shadcn UI Themes 페이지에는 색상을 선택하고 전체 테마 블록을 복사하여 붙여넣을 수 있는 환상적인 생성기가 있습니다. - 테두리 반경 변경: 더 날카로운 모서리를 원하십니까?
--radius: 0.5rem;을--radius: 0.2rem;또는 심지어0rem으로 변경하십시오. 둥근 모서리가 있는 모든 컴포넌트는 이 변수를 사용하므로 변경 사항이 전역적으로 전파됩니다.
다크 모드 구현:
Shadcn은 .dark 클래스 블록과 tailwind.config.ts의 Tailwind의 darkMode: "class" 전략 덕분에 다크 모드를 위해 사전 구성되어 있습니다. 필요한 것은 <html> 요소에 dark 클래스를 토글하는 방법뿐입니다. 이를 위한 인기 있는 라이브러리는 next-themes입니다.
- 설치:
npm install next-themes ThemeProvider컴포넌트 생성 (src/components/theme-provider.tsx): TypeScript
"use client"
import * as React from "react"
import { ThemeProvider as NextThemesProvider } from "next-themes"
import { type ThemeProviderProps } from "next-themes/dist/types"
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}
- 이 프로바이더로
RootLayout래핑 (src/app/layout.tsx): TypeScript
import { ThemeProvider } from "@/components/theme-provider"
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
{children}
<Toaster />
</ThemeProvider>
</body>
</html>
)
}
- 마지막으로 토글 버튼 생성 (예:
src/components/mode-toggle.tsx): TypeScript
"use client"
import * as React from "react"
import { Moon, Sun } from "lucide-react"
import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button"
export function ModeToggle() {
const { theme, setTheme } = useTheme()
return (
<Button
variant="outline"
size="icon"
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
>
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">테마 토글</span>
</Button>
)
}
이제 이 <ModeToggle />을 앱의 어느 곳에든 배치하여 시스템 인식 및 사용자 재정의 가능한 다크 모드 토글을 얻을 수 있습니다.
11단계: 컴포넌트 소스 코드 사용자 정의
이것이 궁극적인 초능력입니다. 버튼에 녹색 배경을 가진 새로운 성공 변형을 원한다고 가정해 봅시다.
src/components/ui/button.tsx를 엽니다. buttonVariants 정의를 찾습니다. cva (Class Variance Authority)를 사용합니다. 단순히 새로운 변형을 추가합니다.TypeScript
const buttonVariants = cva(
// ... 기본 스타일
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
success: "bg-green-600 text-white hover:bg-green-600/90", // 우리의 새로운 변형
},
// ... 크기 변형
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
그게 다입니다. 이제 코드에서 사용할 수 있습니다. <Button variant="success">성공</Button>. 복잡한 CSS 오버라이드를 작성할 필요가 없었습니다. 컴포넌트 자체의 소스 코드만 편집했습니다. 이 워크플로우는 간단하고 예측 가능하며 믿을 수 없을 정도로 강력합니다.
6부: 모범 사례 및 앞으로 나아갈 길
애플리케이션이 성장함에 따라 염두에 두어야 할 몇 가지 모범 사례가 있습니다.
- 파일 구성: CLI는 모든 것을
components/ui에 넣지만, 이 폴더는 "기본" UI 키트로 간주되어야 합니다. 직접 구성하는 더 복잡한 컴포넌트(예: Shadcn의Card,Avatar,Button을 사용하는UserProfileCard)의 경우,components/shared또는components/features와 같은 다른 디렉토리에 생성하십시오. 이렇게 하면 기본 UI와 애플리케이션별 컴포넌트 사이에 명확한 구분이 유지됩니다. - 컴포넌트 업데이트: 원래 Shadcn UI 컴포넌트가 개선되면 어떻게 업데이트를 받을 수 있습니까? CLI가 해결해 줍니다.
npx shadcn-ui@latest add button을 다시 실행할 수 있습니다. CLI는 이미button.tsx파일이 있음을 감지하고diff비교를 보여주어 파일을 덮어쓰거나 변경 사항을 수동으로 수락할 수 있도록 합니다. 컴포넌트의 미니 버전 관리와 같습니다. - 접근성 활용: Shadcn 컴포넌트는 Radix 프리미티브 위에 구축되었기 때문에 기본적으로 접근성이 있습니다. 이를 사용자 정의할 때 이 접근성을 깨뜨리지 않도록 주의하십시오. 예를 들어, 버튼의 색상을 변경하는 경우 텍스트에 충분한 대비가 있는지 확인하십시오. 새 컴포넌트를 구축할 때 Shadcn/Radix가 설정한 패턴을 따라 키보드 탐색 가능성 및 스크린 리더 지원을 유지하도록 노력하십시오.
결론: 여러분이 라이브러리 작성자입니다
이제 Shadcn UI의 핵심 철학부터 시작하여 고급 실제 패턴 구현까지 여정을 마쳤습니다. 그 진정한 혁신은 컴포넌트 자체뿐만 아니라 그것이 나타내는 패러다임 전환임을 보았습니다. 이는 개발자를 라이브러리의 단순한 소비자에서 자신만의 UI 툴킷의 큐레이터 및 소유자로 이동시킵니다.
원시 소스 코드를 제공하고, Tailwind CSS 및 Radix UI의 견고한 기반 위에 구축하며, 원활한 CLI 경험을 제공함으로써 Shadcn UI는 초기 개발 속도와 장기적인 유지보수성 및 창의적 자유 사이에서 완벽한 균형을 이룹니다. 더 이상 다른 사람의 디자인 시스템에 제약받지 않습니다. 프로젝트의 컴포넌트는 수정하고 확장하며 완벽하게 만들 수 있는 여러분 자신의 것입니다.
애플리케이션 UI의 미래는 더 이상 타사 종속성의 손에 달려 있지 않습니다. 바로 components 폴더에 있습니다. 즐거운 구축 되십시오.
개발 팀이 최대 생산성으로 함께 작업할 수 있는 통합된 올인원 플랫폼을 원하십니까?
Apidog는 여러분의 모든 요구 사항을 충족하며, Postman을 훨씬 저렴한 가격으로 대체합니다!
