npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

krds-react-components

v2.0.1

Published

Korea Responsive Design System React Components

Readme

KRDS React Components

KRDS(Korea Responsive Design System)는 대한민국 디지털 정부를 위한 React 컴포넌트 라이브러리입니다. 반응형, 접근성을 갖춘 UI/UX를 빠르고 일관되게 개발할 수 있도록 지원합니다.

📦 설치

npm install krds-react-components styled-components
# 또는
yarn add krds-react-components styled-components
# 또는
pnpm add krds-react-components styled-components

🚀 Next.js에서 사용하기 (Step by Step)

1단계: 프로젝트 생성 및 패키지 설치

# Next.js 프로젝트 생성 (TypeScript 사용 권장)
npx create-next-app@latest my-gov-app --typescript --tailwind --app

# 프로젝트 디렉토리로 이동
cd my-gov-app

# KRDS React Components와 의존성 설치
npm install krds-react-components styled-components

# TypeScript용 타입 정의 설치
npm install -D @types/styled-components

2단계: Next.js Config 설정 (next.config.js)

/** @type {import('next').NextConfig} */
const nextConfig = {
  compiler: {
    // styled-components SSR 지원
    styledComponents: true,
  },
  transpilePackages: ['krds-react-components'],
}

module.exports = nextConfig

3단계: ThemeProvider 설정 (app/providers.tsx)

'use client'

import React from 'react'
import { ThemeProvider as KRDSThemeProvider, GlobalStyles, lightTheme } from 'krds-react-components'
import { ThemeProvider as StyledThemeProvider } from 'styled-components'

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <StyledThemeProvider theme={lightTheme}>
      <KRDSThemeProvider initialMode="light">
        <GlobalStyles />
        {children}
      </KRDSThemeProvider>
    </StyledThemeProvider>
  )
}

4단계: 루트 레이아웃 설정 (app/layout.tsx)

import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import { Providers } from './providers'
import './globals.css'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: '정부 웹사이트',
  description: 'KRDS React Components를 사용한 정부 웹사이트',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="ko">
      <body className={inter.className}>
        <Providers>
          {children}
        </Providers>
      </body>
    </html>
  )
}

5단계: 메인 페이지에서 컴포넌트 사용 (app/page.tsx)

'use client'

import { useState } from 'react'
import { 
  Header, 
  Footer, 
  Layout, 
  Button, 
  Input, 
  Select, 
  Alert,
  Card,
  Table 
} from 'krds-react-components'

export default function Home() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    region: ''
  })

  const navigationItems = [
    { id: 'home', label: '홈', href: '/' },
    { id: 'services', label: '서비스', href: '/services' },
    { id: 'support', label: '민원신청', href: '/support' },
    { id: 'info', label: '정보공개', href: '/info' }
  ]

  const regions = [
    { value: 'seoul', label: '서울특별시' },
    { value: 'busan', label: '부산광역시' },
    { value: 'daegu', label: '대구광역시' },
    { value: 'incheon', label: '인천광역시' }
  ]

  const tableData = [
    { id: 1, title: '시스템 점검 안내', date: '2024-08-14', status: '진행중' },
    { id: 2, title: '신청 서비스 개선', date: '2024-08-13', status: '완료' },
    { id: 3, title: '보안 업데이트', date: '2024-08-12', status: '예정' }
  ]

  const tableColumns = [
    { key: 'title', title: '제목', dataIndex: 'title' },
    { key: 'date', title: '날짜', dataIndex: 'date' },
    { key: 'status', title: '상태', dataIndex: 'status' }
  ]

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault()
    alert(`제출 완료: ${JSON.stringify(formData, null, 2)}`)
  }

  return (
    <Layout>
      {/* 헤더 */}
      <Header 
        logo={{ text: '정부24', href: '/' }}
        navigation={navigationItems}
      />
      
      <main style={{ padding: '2rem 0', minHeight: 'calc(100vh - 200px)' }}>
        <div style={{ maxWidth: '1200px', margin: '0 auto', padding: '0 2rem' }}>
          {/* 페이지 제목 */}
          <div style={{ textAlign: 'center', marginBottom: '3rem' }}>
            <h1>KRDS React Components</h1>
            <p>Next.js에서 한국 반응형 디자인 시스템 사용하기</p>
          </div>

          {/* 알림 */}
          <Alert 
            variant="info" 
            title="환영합니다!"
            style={{ marginBottom: '2rem' }}
          >
            KRDS React Components를 Next.js에서 사용하는 예시입니다.
          </Alert>

          {/* 폼 섹션 */}
          <div style={{ marginBottom: '3rem' }}>
            <h2>신청 폼 예시</h2>
            <form onSubmit={handleSubmit} style={{ maxWidth: '500px' }}>
              <Input
                label="이름"
                value={formData.name}
                onChange={(e) => setFormData(prev => ({ ...prev, name: e.target.value }))}
                placeholder="이름을 입력하세요"
                required
                style={{ marginBottom: '1rem' }}
              />
              
              <Input
                label="이메일"
                type="email"
                value={formData.email}
                onChange={(e) => setFormData(prev => ({ ...prev, email: e.target.value }))}
                placeholder="이메일을 입력하세요"
                required
                style={{ marginBottom: '1rem' }}
              />
              
              <Select
                label="지역"
                options={regions}
                value={formData.region}
                onChange={(value) => setFormData(prev => ({ ...prev, region: value }))}
                placeholder="지역을 선택하세요"
                required
                style={{ marginBottom: '1.5rem' }}
              />
              
              <div style={{ display: 'flex', gap: '1rem' }}>
                <Button type="submit" variant="primary">
                  제출하기
                </Button>
                <Button 
                  type="button" 
                  variant="secondary"
                  onClick={() => setFormData({ name: '', email: '', region: '' })}
                >
                  초기화
                </Button>
              </div>
            </form>
          </div>

          {/* 테이블 섹션 */}
          <div style={{ marginBottom: '3rem' }}>
            <h2>공지사항</h2>
            <Table
              columns={tableColumns}
              dataSource={tableData}
              caption="공지사항 목록"
            />
          </div>

          {/* 버튼 그룹 */}
          <div style={{ marginBottom: '3rem' }}>
            <h2>버튼 예시</h2>
            <div style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap' }}>
              <Button variant="primary">Primary</Button>
              <Button variant="secondary">Secondary</Button>
              <Button variant="tertiary">Tertiary</Button>
              <Button variant="text">Text</Button>
              <Button loading>Loading</Button>
              <Button disabled>Disabled</Button>
            </div>
          </div>
        </div>
      </main>

      {/* 푸터 */}
      <Footer 
        copyright="© 2024 정부24. All rights reserved."
        links={[
          { label: '이용약관', href: '/terms' },
          { label: '개인정보처리방침', href: '/privacy' },
          { label: '접근성 정책', href: '/accessibility' }
        ]}
      />
    </Layout>
  )
}

6단계: 프로젝트 실행

# 개발 서버 실행
npm run dev

# 빌드 (배포 전 확인)
npm run build

# 빌드된 프로젝트 실행
npm start

7단계: TypeScript 설정 최적화 (tsconfig.json)

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "es6"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

8단계: 스타일드 컴포넌트 레지스트리 설정 (선택사항)

SSR 스타일 이슈 해결을 위한 설정:

app/lib/registry.tsx

'use client'
 
import React, { useState } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import { ServerStyleSheet, StyleSheetManager } from 'styled-components'
 
export default function StyledComponentsRegistry({
  children,
}: {
  children: React.ReactNode
}) {
  const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet())
 
  useServerInsertedHTML(() => {
    const styles = styledComponentsStyleSheet.getStyleElement()
    styledComponentsStyleSheet.instance.clearTag()
    return <>{styles}</>
  })
 
  if (typeof window !== 'undefined') return <>{children}</>
 
  return (
    <StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
      {children}
    </StyleSheetManager>
  )
}

app/layout.tsx 업데이트

import StyledComponentsRegistry from './lib/registry'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="ko">
      <body className={inter.className}>
        <StyledComponentsRegistry>
          <Providers>
            {children}
          </Providers>
        </StyledComponentsRegistry>
      </body>
    </html>
  )
}

## 빠른 시작

### 1. 기본 설정

외부 앱에서 KRDS를 사용하려면 먼저 ThemeProvider와 GlobalStyles를 설정해야 합니다.

```tsx
import React from 'react'
import { ThemeProvider } from 'styled-components'
import { lightTheme, GlobalStyles } from 'krds-react-components'

function App() {
  return (
    <ThemeProvider theme={lightTheme}>
      <GlobalStyles />
      <div className="App">
        {/* 여기에 앱 컨텐츠 */}
      </div>
    </ThemeProvider>
  )
}

export default App

2. 폰트 설정

PretendardGOV 폰트는 패키지에 자동으로 포함되어 있습니다. 추가 설정이 필요하지 않습니다.

참고: 인터넷 연결이 필요한 CDN 기반 폰트를 사용합니다. 오프라인 환경에서는 별도 폰트 설정이 필요할 수 있습니다.

3. 기본 컴포넌트 사용

import { Button, Input, Alert } from 'krds-react-components'

function MyPage() {
  return (
    <div>
      <Alert variant="info" title="안내">
        KRDS 컴포넌트 라이브러리에 오신 것을 환영합니다.
      </Alert>
      
      <Input 
        label="이름" 
        placeholder="이름을 입력하세요"
        required
      />
      
      <Button variant="primary" size="large">
        제출하기
      </Button>
    </div>
  )
}

컴포넌트 상세 사용법

Layout Components

Header - 정부 사이트 표준 헤더

import { Header } from 'krds-react-components'

function App() {
  const navigationItems = [
    { id: 'home', label: '홈', href: '/' },
    { id: 'about', label: '소개', href: '/about' },
    { id: 'services', label: '서비스', href: '/services' }
  ]

  const userInfo = {
    name: '홍길동',
    department: '행정안전부',
    isLoggedIn: true
  }

  return (
    <Header
      siteName="정부 웹사이트"
      logoSrc="/logo.png"
      navigationItems={navigationItems}
      userInfo={userInfo}
      showLanguageSwitcher
      onLogoClick={() => window.location.href = '/'}
    />
  )
}

Footer - 정부 사이트 표준 푸터

import { Footer } from 'krds-react-components'

function App() {
  const footerSections = [
    {
      title: '관련 사이트',
      links: [
        { label: '정부24', href: 'https://gov.kr' },
        { label: '국민신문고', href: 'https://epeople.go.kr' }
      ]
    }
  ]

  return (
    <Footer
      siteName="행정안전부"
      address="서울특별시 종로구 세종대로 209"
      phone="02-2100-3000"
      sections={footerSections}
      showAccessibility
    />
  )
}

Data Display Components

Table - 데이터 테이블

import { Table } from 'krds-react-components'

function DataPage() {
  const columns = [
    {
      key: 'name',
      title: '이름',
      dataIndex: 'name',
      width: '20%'
    },
    {
      key: 'department',
      title: '부서',
      dataIndex: 'department'
    },
    {
      key: 'position',
      title: '직책',
      dataIndex: 'position'
    },
    {
      key: 'action',
      title: '작업',
      dataIndex: 'action',
      render: (_, record) => (
        <Button size="small" onClick={() => handleEdit(record.id)}>
          수정
        </Button>
      )
    }
  ]

  const data = [
    { id: 1, name: '홍길동', department: '행정안전부', position: '과장' },
    { id: 2, name: '김철수', department: '국토교통부', position: '주무관' }
  ]

  return (
    <Table
      columns={columns}
      dataSource={data}
      caption="직원 목록 테이블"
      bordered
      striped
      hoverable
    />
  )
}

Tab - 탭 인터페이스

import { Tab } from 'krds-react-components'

function ContentPage() {
  const items = [
    {
      key: 'notice',
      label: '공지사항',
      content: (
        <div>
          <h3>최신 공지사항</h3>
          <p>시스템 점검 안내...</p>
        </div>
      )
    },
    {
      key: 'data',
      label: '자료실',
      content: (
        <div>
          <h3>다운로드 자료</h3>
          <ul>
            <li>사용자 가이드.pdf</li>
            <li>API 문서.pdf</li>
          </ul>
        </div>
      )
    },
    {
      key: 'faq',
      label: 'FAQ',
      content: <div>자주 묻는 질문들...</div>
    }
  ]

  return (
    <Tab
      items={items}
      defaultActiveKey="notice"
      variant="line"
      onChange={(key) => console.log('Active tab:', key)}
    />
  )
}

Accordion - 아코디언

import { Accordion } from 'krds-react-components'

function FAQPage() {
  const items = [
    {
      key: 'faq1',
      header: '서비스 이용 시간은 어떻게 되나요?',
      content: (
        <div>
          <p>24시간 연중무휴로 서비스를 제공합니다.</p>
          <p>단, 매주 일요일 새벽 2시~6시는 시스템 점검 시간입니다.</p>
        </div>
      )
    },
    {
      key: 'faq2',
      header: '비밀번호를 잊어버렸어요',
      content: (
        <div>
          <p>로그인 페이지에서 '비밀번호 찾기'를 클릭하세요.</p>
          <ol>
            <li>본인 확인 절차를 진행합니다</li>
            <li>등록된 이메일로 임시 비밀번호를 발송합니다</li>
            <li>로그인 후 비밀번호를 변경하세요</li>
          </ol>
        </div>
      )
    }
  ]

  return (
    <Accordion
      items={items}
      multiple
      bordered
      collapsible
    />
  )
}

Navigation Components

Breadcrumb - 브레드크럼

import { Breadcrumb } from 'krds-react-components'

function DetailPage() {
  const items = [
    { label: '홈', href: '/' },
    { label: '공지사항', href: '/notice' },
    { label: '시스템 점검 안내' }
  ]

  return (
    <Breadcrumb
      items={items}
      showHome
      separator=">"
      maxItems={4}
    />
  )
}

Pagination - 페이지네이션

import { Pagination } from 'krds-react-components'

function ListPage() {
  const [currentPage, setCurrentPage] = useState(1)
  const totalPages = 20

  return (
    <div>
      {/* 리스트 내용 */}
      
      <Pagination
        currentPage={currentPage}
        totalPages={totalPages}
        onPageChange={setCurrentPage}
        showFirstLast
        showPrevNext
        maxPageButtons={5}
      />
    </div>
  )
}

Feedback Components

Modal - 모달 다이얼로그

import { Modal, Button } from 'krds-react-components'

function ActionPage() {
  const [isDeleteOpen, setIsDeleteOpen] = useState(false)
  const [isInfoOpen, setIsInfoOpen] = useState(false)

  const handleDelete = () => {
    // 삭제 로직
    setIsDeleteOpen(false)
  }

  return (
    <div>
      <Button onClick={() => setIsDeleteOpen(true)} variant="danger">
        삭제
      </Button>
      
      <Button onClick={() => setIsInfoOpen(true)} variant="secondary">
        정보 보기
      </Button>

      {/* 확인 모달 */}
      <Modal
        open={isDeleteOpen}
        title="삭제 확인"
        size="small"
        onClose={() => setIsDeleteOpen(false)}
        footer={
          <div style={{ display: 'flex', gap: '8px', justifyContent: 'flex-end' }}>
            <Button variant="secondary" onClick={() => setIsDeleteOpen(false)}>
              취소
            </Button>
            <Button variant="danger" onClick={handleDelete}>
              삭제
            </Button>
          </div>
        }
      >
        <p>정말로 이 항목을 삭제하시겠습니까?</p>
        <p>삭제된 데이터는 복구할 수 없습니다.</p>
      </Modal>

      {/* 정보 모달 */}
      <Modal
        open={isInfoOpen}
        title="상세 정보"
        size="medium"
        onClose={() => setIsInfoOpen(false)}
      >
        <div>
          <h4>서비스 안내</h4>
          <p>본 서비스는 정부24와 연계하여 제공됩니다.</p>
        </div>
      </Modal>
    </div>
  )
}

Form 통합 예제

import { 
  Input, Select, Checkbox, Radio, Textarea, Switch, Button, Alert 
} from 'krds-react-components'

function RegisterForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    region: '',
    gender: '',
    agreement: false,
    notifications: true,
    description: ''
  })
  
  const [errors, setErrors] = useState({})

  const regions = [
    { value: 'seoul', label: '서울특별시' },
    { value: 'busan', label: '부산광역시' },
    { value: 'daegu', label: '대구광역시' },
    { value: 'incheon', label: '인천광역시' }
  ]

  const handleSubmit = (e) => {
    e.preventDefault()
    // 폼 제출 로직
  }

  return (
    <form onSubmit={handleSubmit}>
      <Alert variant="info" title="회원가입 안내">
        모든 필수 항목을 입력해주세요.
      </Alert>

      <Input
        label="이름"
        value={formData.name}
        onChange={(e) => setFormData(prev => ({ ...prev, name: e.target.value }))}
        required
        state={errors.name ? 'error' : undefined}
        errorMessage={errors.name}
      />

      <Input
        label="이메일"
        type="email"
        value={formData.email}
        onChange={(e) => setFormData(prev => ({ ...prev, email: e.target.value }))}
        required
        state={errors.email ? 'error' : undefined}
        errorMessage={errors.email}
      />

      <Select
        label="지역"
        options={regions}
        value={formData.region}
        onChange={(value) => setFormData(prev => ({ ...prev, region: value }))}
        placeholder="지역을 선택하세요"
        required
      />

      <fieldset>
        <legend>성별</legend>
        <Radio
          name="gender"
          value="male"
          label="남성"
          checked={formData.gender === 'male'}
          onChange={(value) => setFormData(prev => ({ ...prev, gender: value }))}
        />
        <Radio
          name="gender"
          value="female"
          label="여성"
          checked={formData.gender === 'female'}
          onChange={(value) => setFormData(prev => ({ ...prev, gender: value }))}
        />
      </fieldset>

      <Textarea
        label="자기소개"
        value={formData.description}
        onChange={(e) => setFormData(prev => ({ ...prev, description: e.target.value }))}
        placeholder="간단한 자기소개를 입력하세요"
        maxLength={500}
        showCount
      />

      <Checkbox
        label="이용약관에 동의합니다"
        checked={formData.agreement}
        onChange={(checked) => setFormData(prev => ({ ...prev, agreement: checked }))}
        required
      />

      <Switch
        label="알림 받기"
        checked={formData.notifications}
        onChange={(checked) => setFormData(prev => ({ ...prev, notifications: checked }))}
        checkedLabel="켜짐"
        uncheckedLabel="꺼짐"
      />

      <div style={{ marginTop: '24px' }}>
        <Button type="submit" variant="primary" size="large" fullWidth>
          회원가입
        </Button>
      </div>
    </form>
  )
}

컴포넌트

Button

import { Button } from 'krds-react-components'

<Button variant="primary" size="large">
  기본 버튼
</Button>

<Button variant="secondary" disabled>
  비활성화 버튼
</Button>

<Button variant="text" loading>
  로딩 중...
</Button>

Badge

import { Badge } from 'krds-react-components'

<Badge variant="primary">Label</Badge>
<Badge variant="danger" count={5} />
<Badge variant="success" dot />

Form Components

Input

import { Input } from 'krds-react-components'

<Input 
  label="이름" 
  placeholder="이름을 입력하세요"
  required
/>

<Input 
  label="이메일" 
  type="email"
  state="error"
  errorMessage="올바른 이메일을 입력하세요"
/>

Checkbox

import { Checkbox } from 'krds-react-components'

<Checkbox label="이용약관 동의" required />
<Checkbox 
  label="마케팅 수신 동의" 
  description="선택사항입니다"
/>

Radio

import { Radio, RadioGroup } from 'krds-react-components'

<RadioGroup name="gender" defaultValue="male">
  <Radio value="male" label="남성" />
  <Radio value="female" label="여성" />
  <Radio value="other" label="기타" />
</RadioGroup>

Select

import { Select } from 'krds-react-components'

<Select 
  label="지역 선택"
  placeholder="지역을 선택하세요"
  options={[
    { value: 'seoul', label: '서울' },
    { value: 'busan', label: '부산' },
    { value: 'daegu', label: '대구' }
  ]}
/>

Textarea

import { Textarea } from 'krds-react-components'

<Textarea 
  label="의견"
  placeholder="의견을 입력하세요"
  maxLength={500}
  showCount
/>

Switch

import { Switch } from 'krds-react-components'

<Switch label="알림 받기" />
<Switch 
  label="다크 모드"
  checkedLabel="켜짐"
  uncheckedLabel="꺼짐"
/>

테마

라이트 모드

기본 테마로 일반적인 사용 환경에 적합합니다.

고대비 모드

시각적 접근성이 필요한 사용자를 위한 테마입니다.

<ThemeProvider initialMode="high-contrast">
  <App />
</ThemeProvider>

접근성

KRDS React는 웹 접근성 지침(WCAG 2.1)을 준수하여 개발되었습니다:

  • 키보드 내비게이션 지원
  • 스크린 리더 호환
  • 고대비 모드 지원
  • 적절한 ARIA 속성

개발

# 개발 서버 시작 (Storybook)
npm run dev

# 빌드
npm run build

# 테스트
npm test

# 린트
npm run lint

테마 커스터마이징

기본 테마를 확장하여 사용할 수 있습니다:

import { lightTheme } from 'krds-react-components'

const customTheme = {
  ...lightTheme,
  colors: {
    ...lightTheme.colors,
    primary: {
      ...lightTheme.colors.primary,
      50: '#1a73e8' // 사용자 정의 색상
    }
  },
  spacing: {
    ...lightTheme.spacing,
    custom: '2.5rem' // 사용자 정의 간격
  }
}

// ThemeProvider에 customTheme 사용
<ThemeProvider theme={customTheme}>
  <App />
</ThemeProvider>

고대비 모드

시각적 접근성이 필요한 사용자를 위한 고대비 테마를 제공합니다:

import { highContrastTheme } from 'krds-react-components'

<ThemeProvider theme={highContrastTheme}>
  <App />
</ThemeProvider>

TypeScript 지원

모든 컴포넌트는 완전한 TypeScript 지원을 제공합니다:

import { ButtonProps, InputProps, TableColumn } from 'krds-react-components'

// 컴포넌트 props 타입 확장
interface CustomButtonProps extends ButtonProps {
  customProp?: string
}

// 테이블 컬럼 타입 정의
const columns: TableColumn[] = [
  {
    key: 'name',
    title: '이름',
    dataIndex: 'name',
    render: (value: string) => <strong>{value}</strong>
  }
]

패키지 빌드 및 배포

개발환경 설정

# 의존성 설치
npm install

# 개발 서버 시작 (Storybook)
npm run dev

# 빌드
npm run build

# 테스트
npm test

# 린트
npm run lint

# 타입 체크
npm run type-check

NPM 배포

# 빌드
npm run build

# 배포
npm publish

다른 프로젝트에서 사용

# 설치
npm install krds-react-components styled-components

# 또는 로컬 개발용
npm install file:../krds-react

접근성

KRDS 컴포넌트는 웹 접근성 지침(WCAG 2.1 AA)을 준수합니다:

지원하는 접근성 기능

  • 키보드 내비게이션: 모든 인터랙티브 요소는 키보드로 접근 가능
  • 스크린 리더 호환: 적절한 ARIA 속성과 시맨틱 마크업 사용
  • 색상 대비: WCAG AA 기준 이상의 색상 대비 제공
  • 포커스 관리: 명확한 포커스 표시 및 논리적 탭 순서
  • 다국어 지원: 한국어 기본, 영어 지원

접근성 사용 예제

// 스크린 리더용 텍스트
<Button>
  저장
  <span className="sr-only">현재 문서를</span>
</Button>

// ARIA 레이블 사용
<Input
  label="검색어"
  aria-describedby="search-help"
/>
<div id="search-help">
  검색할 키워드를 입력하세요
</div>

// 키보드 단축키 지원
<Modal>
  <p>ESC 키를 눌러 모달을 닫을 수 있습니다.</p>
</Modal>

브라우저 지원

  • Chrome (최신 2개 버전)
  • Firefox (최신 2개 버전)
  • Safari (최신 2개 버전)
  • Edge (최신 2개 버전)
  • Internet Explorer 11+

성능 최적화

Tree Shaking

필요한 컴포넌트만 import하여 번들 크기를 최적화할 수 있습니다:

// ✅ 권장: 개별 import
import { Button } from 'krds-react-components/Button'
import { Input } from 'krds-react-components/Input'

// ✅ 가능: 전체 import (Tree shaking 지원)
import { Button, Input } from 'krds-react-components'

// ❌ 비권장: 전체 라이브러리 import
import * as KRDS from 'krds-react-components'

코드 분할

import { lazy, Suspense } from 'react'

// 필요한 시점에 로드
const Table = lazy(() => import('krds-react-components/Table'))

function DataPage() {
  return (
    <Suspense fallback={<div>로딩 중...</div>}>
      <Table columns={columns} dataSource={data} />
    </Suspense>
  )
}

문제 해결

스타일이 적용되지 않는 경우

  1. ThemeProvider가 올바르게 설정되었는지 확인
  2. GlobalStyle이 포함되었는지 확인
  3. styled-components 버전 호환성 확인
// 올바른 설정
import { ThemeProvider } from 'styled-components'
import { lightTheme, GlobalStyles } from 'krds-react-components'

<ThemeProvider theme={lightTheme}>
  <GlobalStyles />
  <App />
</ThemeProvider>

TypeScript 오류

  1. @types/styled-components 설치 확인
  2. tsconfig.json 설정 확인
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true
  }
}

라이센스

MIT License

기여하기

  1. 이 저장소를 Fork합니다
  2. 기능 브랜치를 생성합니다 (git checkout -b feature/amazing-feature)
  3. 변경사항을 커밋합니다 (git commit -m 'Add some amazing feature')
  4. 브랜치에 Push합니다 (git push origin feature/amazing-feature)
  5. Pull Request를 생성합니다

지원 및 문의

변경 이력

v1.0.0 (2025-08-14)

  • 🎉 초기 릴리즈
  • ✨ 모든 기본 컴포넌트 포함 (Button, Input, Table, Modal 등)
  • 🎨 KRDS 디자인 시스템 완전 구현
  • ♿ WCAG 2.1 AA 접근성 기준 준수
  • 🔧 TypeScript 완전 지원
  • 📱 반응형 디자인 지원
  • 🌙 라이트/고대비 테마 지원
  • 📚 Storybook 문서화