모든 강의를 무료로 볼 수 있어요. 회원가입 없이도 학습 가능합니다.

28강 / 전체 30강

배포하기

4분 읽기 조회 3

컴포넌트 라이브러리(shadcn/ui, Radix UI) 활용법과 스타일 시스템 구축, 접근성(a11y) 원칙, 그리고 디자인 시스템 없이도 일관된 UI를 만드는 방법을 배웁니다.

🎨 왜 컴포넌트 라이브러리를 쓰는가

버튼, 모달, 드롭다운, 날짜 선택기 등 복잡한 UI 컴포넌트를 처음부터 직접 만들면 많은 시간이 걸립니다. 특히 키보드 탐색, 스크린 리더 지원, 포커스 트랩 같은 접근성 기능까지 직접 구현하는 것은 매우 어렵습니다. 컴포넌트 라이브러리를 활용하면 이 문제를 해결합니다.

📦 shadcn/ui — 현재 가장 인기있는 선택

shadcn/ui는 기존 컴포넌트 라이브러리와 다릅니다. 코드를 당신의 프로젝트에 직접 복사합니다. npm 패키지가 아닙니다. 그래서 완전히 커스터마이징 가능합니다.

# 초기 설정 (Vite 프로젝트)
npx shadcn@latest init

# 필요한 컴포넌트 추가
npx shadcn@latest add button
npx shadcn@latest add dialog
npx shadcn@latest add input

설치하면 src/components/ui/에 컴포넌트 코드가 생깁니다. 직접 수정해서 쓸 수 있습니다.

import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from '@/components/ui/dialog'

function App() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button variant="outline">모달 열기</Button>
      </DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>설정</DialogTitle>
        </DialogHeader>
        <div className="space-y-4 py-4">
          <div>
            <label className="text-sm font-medium">이름</label>
            <Input placeholder="이름을 입력하세요" className="mt-1" />
          </div>
          <Button className="w-full">저장</Button>
        </div>
      </DialogContent>
    </Dialog>
  )
}

♿ 접근성(a11y) 기본 원칙

좋은 UI는 마우스 없이도 키보드만으로 사용할 수 있어야 합니다. shadcn/ui는 Radix UI 위에 구축되어 접근성이 이미 내장되어 있습니다. 직접 컴포넌트를 만들 때 지켜야 할 기본 규칙:

// ❌ 접근성 없는 버튼 — 키보드 사용 불가, 스크린 리더 설명 없음
<div onClick={handleDelete} className="cursor-pointer text-red-500">
  삭제
</div>

// ✅ 시맨틱 요소 사용
<button
  onClick={handleDelete}
  aria-label="게시글 삭제"  // 아이콘만 있을 때 레이블 제공
  className="text-red-500 hover:text-red-700"
>
  <Trash2 className="h-4 w-4" />
</button>

// ✅ 이미지 alt 텍스트
<img src="/avatar.jpg" alt="김민준 프로필 사진" />  // 의미 있는 설명
<img src="/decoration.png" alt="" />               // 장식용은 빈 문자열
원칙실천 방법
시맨틱 HTMLbutton은 <button>, 링크는 <a>, 입력은 <input>
키보드 접근모든 인터랙션이 Tab, Enter, Space, Esc로 동작해야 함
포커스 표시outline을 지우지 마세요 (접근성 필수)
색 대비텍스트와 배경 대비 4.5:1 이상 (WCAG AA)
ARIA 레이블아이콘 버튼에 aria-label 추가

🎭 cn() 유틸리티 — Tailwind 클래스 병합

조건부 클래스와 기본 클래스를 깔끔하게 병합합니다:

// lib/utils.ts (shadcn/ui가 자동 생성)
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

// 사용
function Badge({ variant = 'default' }: { variant?: 'default' | 'success' | 'danger' }) {
  return (
    <span
      className={cn(
        'inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium',
        {
          'bg-gray-100 text-gray-700': variant === 'default',
          'bg-green-100 text-green-700': variant === 'success',
          'bg-red-100 text-red-700': variant === 'danger',
        }
      )}
    >
      {/* ... */}
    </span>
  )
}

✅ 정리

  • shadcn/ui: 코드를 프로젝트에 복사해 사용 — 완전 커스터마이징 가능.
  • Radix UI 기반으로 키보드, 스크린 리더, 포커스 관리가 내장되어 있습니다.
  • 직접 컴포넌트 만들 때: 시맨틱 HTML + aria 속성 + 키보드 동작을 반드시 챙기세요.
  • cn()으로 조건부 Tailwind 클래스를 깔끔하게 병합합니다.

관련 주제

  • shadcn/ui
  • Radix UI
  • 컴포넌트 라이브러리
  • 접근성
  • 키보드 탐색
  • 스크린 리더
  • 커스터마이징
  • 개발·프로그래밍
  • 개발·프로그래밍 강의
  • 리액트 입문 — 컴포넌트로 만드는 웹
  • 무료강의
  • 무료 온라인 강의
  • NUGUNA
  • 누구나

📚 시리즈 전체 공유

리액트 입문 — 컴포넌트로 만드는 웹

이 강의가 속한 시리즈는 총 30강, 모두 무료입니다. 처음부터 배우려는 동료에게 시리즈 전체를 알려 주세요.

댓글

0/1000

불러오는 중...