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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jiin.seok/formkit-react

v0.6.3

Published

A powerful React form library with Compound Component Pattern, built-in validation, and TypeScript support

Downloads

2,225

Readme

@jiin.seok/formkit-react

🚀 Compound Component Pattern과 내장 검증, TypeScript 지원을 갖춘 강력한 React 폼 라이브러리

npm version License: MIT

English Documentation

✨ 주요 기능

  • 🎯 Compound Component Pattern - 깔끔하고 조합 가능한 API
  • 🔄 React Hook Form 통합 - 성능 최적화
  • 🛡️ Zod 스키마 지원 - 타입 안전 검증
  • ♿ 접근성 우선 - ARIA 준수
  • 🎨 켜고 끄는 기본 테마 - 스타일시트를 불러오면 바로 쓸 만한 모양, 안 불러오면 순수 HTML
  • 📝 TypeScript - 완전한 타입 안정성
  • 🔒 비밀번호 토글 - 내장 가시성 토글
  • 🎛️ Select 컴포넌트 - Radix UI 기반

📦 설치

npm install @jiin.seok/formkit-react
# 또는
yarn add @jiin.seok/formkit-react
# 또는
pnpm add @jiin.seok/formkit-react

Peer Dependencies

npm install react react-dom

react-hook-form, zod, @hookform/resolvers 등은 패키지 의존성으로 자동 설치됩니다.

스타일 불러오기

기본 테마를 쓰려면 앱 진입점(예: main.tsx, layout.tsx)에서 한 번 불러옵니다.

import '@jiin.seok/formkit-react/styles.css'

이 줄을 넣지 않으면 컴포넌트는 아무 스타일도 얹지 않은 순수 HTML로 그려집니다. 처음부터 직접 그리고 싶으면 불러오지 않으면 됩니다. 스타일시트는 Tailwind를 요구하지 않으므로 어떤 앱에서도 동작합니다.

🚀 빠른 시작

기본 예제

import FormKit from '@jiin.seok/formkit-react'

function LoginForm() {
  const handleSubmit = (data) => {
    console.log('폼 데이터:', data)
  }

  return (
    <FormKit.Root formId="login" onSubmit={handleSubmit}>
      <FormKit.Title>로그인</FormKit.Title>
      
      <FormKit.Field>
        <FormKit.Label>이메일</FormKit.Label>
        <FormKit.Input name="email" type="email" required />
      </FormKit.Field>
      
      <FormKit.Field>
        <FormKit.Label>비밀번호</FormKit.Label>
        <FormKit.Input name="password" type="password" required />
      </FormKit.Field>
      
      <FormKit.SubmitButton>로그인</FormKit.SubmitButton>
    </FormKit.Root>
  )
}

Zod 검증과 함께 사용

import FormKit from '@jiin.seok/formkit-react'
import { z } from 'zod'

const loginSchema = z.object({
  email: z.string().email('유효하지 않은 이메일 주소입니다'),
  password: z.string().min(8, '비밀번호는 최소 8자 이상이어야 합니다')
})

function LoginForm() {
  const handleSubmit = (data) => {
    console.log('검증된 데이터:', data)
  }

  return (
    <FormKit.Root 
      formId="login" 
      schema={loginSchema} 
      onSubmit={handleSubmit}
    >
      <FormKit.Field>
        <FormKit.Label>이메일</FormKit.Label>
        <FormKit.Input name="email" type="email" />
      </FormKit.Field>
      
      <FormKit.Field>
        <FormKit.Label>비밀번호</FormKit.Label>
        <FormKit.Input name="password" type="password" />
      </FormKit.Field>
      
      <FormKit.SubmitButton>로그인</FormKit.SubmitButton>
    </FormKit.Root>
  )
}

Select를 포함한 고급 폼

import FormKit from '@jiin.seok/formkit-react'

function RegistrationForm() {
  const countries = [
    { value: 'kr', label: '대한민국' },
    { value: 'us', label: '미국' },
    { value: 'jp', label: '일본' },
  ]

  return (
    <FormKit.Root formId="registration" onSubmit={handleSubmit}>
      <FormKit.Fieldset>
        <FormKit.Legend required>개인 정보</FormKit.Legend>
        
        <FormKit.Field>
          <FormKit.Label>이름</FormKit.Label>
          <FormKit.Input name="fullName" required />
        </FormKit.Field>
        
        <FormKit.Field>
          <FormKit.Label>국가</FormKit.Label>
          <FormKit.Select 
            name="country" 
            options={countries}
            placeholder="국가를 선택하세요"
            required
          />
        </FormKit.Field>
        
        <FormKit.Field>
          <FormKit.Label>자기소개</FormKit.Label>
          <FormKit.Textarea 
            name="bio" 
            placeholder="간단한 자기소개를 작성해주세요"
            maxLength={500}
          />
        </FormKit.Field>
      </FormKit.Fieldset>
      
      <FormKit.SubmitButton>가입하기</FormKit.SubmitButton>
    </FormKit.Root>
  )
}

📦 사용 가능한 컴포넌트

FormKit은 포괄적인 폼 컴포넌트 세트를 제공합니다:

📝 핵심 컴포넌트

  • FormKit.Root - 검증 컨텍스트를 포함한 메인 폼 컨테이너
  • FormKit.Field - 레이블-입력 연결이 있는 필드 래퍼
  • FormKit.Fieldset - 관련된 필드 그룹화
  • FormKit.Legend - 필수 표시가 선택적으로 포함된 필드셋 제목

🎨 입력 컴포넌트

  • FormKit.Input - 비밀번호 토글, 이메일, 숫자 등을 지원하는 텍스트 입력
  • FormKit.Textarea - 여러 줄 텍스트 입력
  • FormKit.Select - 검색 기능이 있는 드롭다운 선택 (Radix UI 기반)

🏷️ 표시 컴포넌트

  • FormKit.Label - 필드 레이블
  • FormKit.Description - 입력 예시·형식 안내
  • FormKit.Title - 폼 제목
  • FormKit.Wrapper - 커스텀 레이아웃용 컨테이너
  • FormKit.Unit - 단위 표시 (예: "원", "kg")
  • FormKit.Error - 오류 메시지 표시

🎯 액션 컴포넌트

  • FormKit.SubmitButton - 로딩 상태가 있는 제출 버튼
  • FormKit.ResetButton - 폼을 초기값으로 재설정

📚 API 레퍼런스

FormKit.Root

모든 자식 컴포넌트에 컨텍스트를 제공하는 메인 폼 컨테이너입니다.

| Prop | Type | 필수 | 설명 | |------|------|------|------| | formId | string | ✅ | 폼의 고유 식별자 | | onSubmit | (data) => void | ✅ | 폼 제출 핸들러 | | schema | ZodSchema | ❌ | 검증을 위한 Zod 스키마 | | defaultValues | object | ❌ | 기본 폼 값 | | locale | 'ko' \| 'en' | ❌ | 자동 노출 문구(Select placeholder·비밀번호 aria-label)의 기본 언어. 기본값 'en' | | messages | Partial<FormMessages> | ❌ | 개별 문구만 덮어쓰기. locale 기본값 위에 얕게 병합됨 |

// 폼 전체의 기본 문구를 한국어로
<FormKit.Root formId="signup" locale="ko" onSubmit={onSubmit}>
  {/* Select 기본 placeholder가 '옵션을 선택하세요'로 나온다 */}
  <FormKit.Select name="genre" options={options} />
</FormKit.Root>

// 특정 문구만 커스텀
<FormKit.Root
  formId="signup"
  locale="ko"
  messages={{ selectPlaceholder: '장르를 골라주세요' }}
  onSubmit={onSubmit}
/>

FormKit.Field

자동 레이블-입력 연결이 있는 폼 입력용 컨테이너입니다.

| Prop | Type | 기본값 | 설명 | |------|------|--------|------| | isInline | boolean | false | 레이블과 입력을 가로로 표시 | | hidden | boolean | false | 필드 숨기기 | | htmlFor | string | auto | 레이블-입력 연결을 위한 커스텀 ID |

FormKit.Input

내장 기능이 있는 향상된 입력 컴포넌트입니다.

| Prop | Type | 필수 | 설명 | |------|------|------|------| | name | string | ✅ | 필드 이름 | | type | string | ❌ | 입력 타입 (text, email, password 등) | | required | boolean | ❌ | 필드를 필수로 표시 | | minLength | number | ❌ | 최소 문자 길이 | | maxLength | number | ❌ | 최대 문자 길이 |

기능:

  • 🔒 type="password"에 대한 자동 비밀번호 가시성 토글
  • ✅ 확인 필드에 대한 자동 검증 (예: confirmPassword)
  • 🎯 완전한 TypeScript 지원

FormKit.Select

Radix UI를 사용한 드롭다운 선택 컴포넌트입니다.

| Prop | Type | 필수 | 설명 | |------|------|------|------| | name | string | ✅ | 필드 이름 | | options | Array<{value, label}> | ✅ | 선택 옵션 | | placeholder | string | ❌ | 플레이스홀더 텍스트. 넘기지 않으면 FormKit.Root의 locale에 맞는 기본값 사용 | | required | boolean | ❌ | 필드를 필수로 표시 |

FormKit.Textarea

여러 줄 텍스트 입력 컴포넌트입니다.

| Prop | Type | 필수 | 설명 | |------|------|------|------| | name | string | ✅ | 필드 이름 | | required | boolean | ❌ | 필드를 필수로 표시 | | minLength | number | ❌ | 최소 문자 길이 | | maxLength | number | ❌ | 최대 문자 길이 | | rows | number | ❌ | 표시되는 텍스트 줄 수 (기본값: 4) |

FormKit.Fieldset

관련된 폼 필드를 함께 그룹화합니다.

| Prop | Type | 필수 | 설명 | |------|------|------|------| | className | string | ❌ | 커스텀 CSS 클래스 | | children | ReactNode | ✅ | 자식 컴포넌트 |

FormKit.Legend

필수 표시가 선택적으로 있는 필드셋 제목입니다.

| Prop | Type | 필수 | 설명 | |------|------|------|------| | required | boolean | ❌ | 빨간색 별표(*) 표시 | | className | string | ❌ | 커스텀 CSS 클래스 | | children | ReactNode | ✅ | 범례 텍스트 |

FormKit.Label

폼 입력을 위한 접근 가능한 레이블입니다.

| Prop | Type | 필수 | 설명 | |------|------|------|------| | className | string | ❌ | 커스텀 CSS 클래스 | | children | ReactNode | ✅ | 레이블 텍스트 |

FormKit.Description

입력 예시나 형식을 안내하는 설명입니다. 같은 Field 안의 입력이 aria-describedby로 이 설명을 가리키므로, 스크린리더는 칸에 들어갔을 때 설명을 함께 읽습니다. 오류가 함께 있으면 설명과 오류를 모두 가리킵니다.

설명은 칸 이름에는 섞이지 않습니다. Field가 label이라 그냥 두면 이름이 "예상 인원 수업에 참여하실 어르신 수"처럼 길어져, 칸 목록을 훑을 때 방해가 되기 때문입니다.

<FormKit.Field>
  <FormKit.Legend required>예상 인원</FormKit.Legend>
  <FormKit.Description>수업에 참여하실 어르신 수</FormKit.Description>
  <FormKit.Input name="headcount" type="number" required />
</FormKit.Field>

| Prop | Type | 필수 | 설명 | |------|------|------|------| | className | string | ❌ | 커스텀 CSS 클래스 | | children | ReactNode | ✅ | 설명 텍스트 |

FormKit.Title

폼 제목/헤더 컴포넌트입니다.

| Prop | Type | 필수 | 설명 | |------|------|------|------| | className | string | ❌ | 커스텀 CSS 클래스 | | children | ReactNode | ✅ | 제목 텍스트 |

FormKit.SubmitButton

내장 로딩 상태가 있는 제출 버튼입니다.

| Prop | Type | 필수 | 설명 | |------|------|------|------| | variant | string | ❌ | 버튼 스타일 변형 | | disabled | boolean | ❌ | 버튼 비활성화 | | className | string | ❌ | 커스텀 CSS 클래스 | | children | ReactNode | ✅ | 버튼 텍스트 |

FormKit.ResetButton

폼을 초기값으로 재설정합니다.

| Prop | Type | 필수 | 설명 | |------|------|------|------| | onClick | function | ❌ | 추가 클릭 핸들러 | | className | string | ❌ | 커스텀 CSS 클래스 | | children | ReactNode | ✅ | 버튼 텍스트 |

FormKit.Wrapper

커스텀 레이아웃용 컨테이너 컴포넌트입니다.

| Prop | Type | 필수 | 설명 | |------|------|------|------| | className | string | ❌ | 커스텀 CSS 클래스 | | children | ReactNode | ✅ | 자식 컴포넌트 |

FormKit.Unit

입력 필드 옆에 단위를 표시합니다.

| Prop | Type | 필수 | 설명 | |------|------|------|------| | unit | string | ✅ | 단위 텍스트 (예: "원", "kg", "%") |

FormKit.Error

검증 오류 메시지를 표시합니다.

| Prop | Type | 필수 | 설명 | |------|------|------|------| | error | FieldError | ❌ | react-hook-form의 오류 객체 |

🎨 스타일링

색 바꾸기

기본 테마는 호스트 앱의 CSS 변수를 먼저 읽고, 없을 때만 자체 기본값으로 떨어집니다. :root에 아래 변수 중 있는 것만 정의하면 그대로 반영됩니다. 값은 완전한 색상값(oklch(...)·hsl(...)· #hex)으로 씁니다.

:root {
  --primary: oklch(0.53 0.15 215); /* 강조색: 기본 버튼·초점 테두리·필수 표시 */
  --primary-foreground: oklch(0.99 0 0); /* 강조색 위 글자 */
  --background: oklch(1 0 0); /* 초점이 온 입력칸 배경 */
  --foreground: oklch(0.24 0.015 270); /* 본문 글자 */
  --muted-foreground: oklch(0.52 0.012 270); /* 안내문·플레이스홀더 */
  --input: oklch(0.9 0.006 270); /* 테두리 */
  --destructive: oklch(0.55 0.2 25); /* 오류 */
}

곡률·컨트롤 높이는 --fk- 변수로 바꿉니다.

:root {
  --fk-radius: 0.625rem;
  --fk-control-height: 2.75rem;
}

클래스로 덮어쓰기

컴포넌트는 className을 그대로 흘려보내고, 기본 모양은 @layer formkit 안에서만 그립니다. 레이어에 든 규칙은 레이어 밖 규칙과 프레임워크 유틸리티에 항상 지므로, 넘긴 클래스는 이름이 무엇이든 특이성이 얼마든 기본값을 이깁니다.

<FormKit.Input name="email" className="rounded-none border-2 border-black" />

Tailwind를 쓰지 않는 앱이면 평범한 CSS 클래스를 넘겨도 같습니다.

🧪 테스팅

import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import FormKit from '@jiin.seok/formkit-react'

test('폼 데이터 제출', async () => {
  const handleSubmit = jest.fn()
  
  render(
    <FormKit.Root formId="test" onSubmit={handleSubmit}>
      <FormKit.Field>
        <FormKit.Input name="username" />
      </FormKit.Field>
      <FormKit.SubmitButton>제출</FormKit.SubmitButton>
    </FormKit.Root>
  )
  
  await userEvent.type(screen.getByRole('textbox'), 'john')
  await userEvent.click(screen.getByRole('button'))
  
  expect(handleSubmit).toHaveBeenCalledWith({ username: 'john' })
})

📄 라이선스

MIT © [Jiin Seok]

🔗 링크