Get startedFoundationsComponentsPatternsRules

Form

폼은 사용자가 정보를 입력하고 제출하도록 필드·라벨·메시지·레이아웃을 묶어 줘요.

설치

pnpm dlx shadcn@latest add https://rebar.conmarket-landing.workers.dev/r/steel/form.json

Anatomy

컴포넌트역할
Form<form> 을 렌더링하고 필드 검증·제출 상태를 관리해요.
Field라벨, 필수 별표, 입력 요소, 도움말·오류·확인 메시지를 한 묶음으로 만들어요.
Label / RequiredAsterisk필드 라벨과 빨간 별표(*)
HelperMessage / ErrorMessage / ValidMessage필드 아래 메시지. 각각 text.subtlest · text.danger · text.success 색이에요.
Fieldset체크박스 묶음처럼 여러 입력을 legend 와 함께 묶어요.
FormHeader / FormSection / FormFooter제목·설명, 구역, 제출 버튼 영역
CharacterCounter남은 글자 수를 실시간으로 알려줘요.

Examples

Basic

Form 의 children 에 JSX 를 바로 넣거나, ({ formProps, submitting }) => … 함수로 <form> 을 직접 렌더링할 수 있어요. onSubmit 이 Promise 를 반환하면 그동안 submitting 이 true 라서 버튼에 로딩을 보여줄 수 있어요. 맨 위 미리보기가 함수 방식 예제예요.

Simplified field

Field 의 children 슬롯에 입력 요소 하나를 넣으면 id, name, aria-labelledby, aria-describedby, aria-invalid 가 자동으로 연결돼요. 메시지는 helperMessage, errorMessage, validMessage props 로 정해요.

메시지가 새로 나타나면 아래 2px 에서 올라오며 150ms 동안 페이드 인하고, 사라질 때는 100ms 동안 아래로 2px 내려가며 페이드 아웃해요 (motion.form.message.enter / exit). 메시지 줄 높이도 함께 펼쳐지고 접혀서 아래 필드가 튀지 않아요. 오류가 확인 메시지로 바뀌는 것처럼 메시지가 동시에 교체되거나 제출 때문에 바뀌면 모션 없이 바로 바꿔요. 동작 줄이기(prefers-reduced-motion) 설정에서는 움직이지 않아요.

Layout

FormHeader 로 제목과 설명을, FormSection 으로 관련 필드를 묶고, FormFooter 에 제출 버튼을 둬요. 단일 페이지 폼은 align="start", 모달 안의 폼은 기본값 end 를 써요.

Fieldset

Fieldset 의 legend 로 같은 이름을 공유하는 체크박스 묶음에 제목을 붙여요. 같은 이름의 값은 배열로 제출돼요.

Field-level validation

validate 는 포커스를 벗어날 때와 제출할 때 실행돼요. 오류 문자열을 반환하면 오류 상태가 되고, 한 번 건드린 필드는 입력할 때마다 다시 검사해서 조건을 만족하면 바로 오류를 지워요. 제출할 때 오류가 있으면 첫 번째 오류 필드로 포커스를 옮겨요.

Submission validation

서버에서만 확인할 수 있는 오류는 onSubmit 에서 { 필드이름: '오류 메시지' } 를 반환해 보여줘요.

Disabled

Form 에 isDisabled 를 주면 안의 모든 Field 가 비활성이 돼요.

Character counter

CharacterCounter 는 최대 글자 수까지 남은 수, 초과한 수, 최소 글자 수까지 부족한 수를 보여줘요. Field 안에서는 입력 id 가 자동으로 연결돼요. children 함수로 fieldProps 를 직접 펼치는 방식도 함께 보여줘요.

Usage guidelines

폼은 개인 설정을 바꾸거나 이슈를 만들 때처럼 사용자가 정보를 입력하고 제출해야 할 때 써요. 텍스트 필드, 텍스트 영역, 셀렉트, 라디오, 체크박스, 날짜 선택, 토글, 범위, 버튼을 담을 수 있어요.

레이아웃

  • 폼 너비는 보통 폼이 놓인 컨테이너(모달, 페이지)를 따라가요.
  • 한 열로 배치해요. 여러 열은 흐름을 따라가기 어렵고 화면 확대 사용자가 내용을 놓치기 쉬워요.
  • 관련 있는 필드는 FormSection 으로 묶고 짧은 제목을 붙여요.
  • 필드 너비는 들어갈 내용 길이에 맞춰요.
Do· 한 열 배치
필드를 위에서 아래로 한 줄씩 쌓아요.
Don't· 여러 열 배치
관련 없는 필드를 나란히 두면 읽는 순서가 헷갈려요.

필드와 라벨

  • 꼭 필요한 정보만 물어요. 선택 입력은 가능하면 줄여요.
  • 맥락에 맞는 기본값을 미리 채워요. 아무 값이나 미리 선택해 두지 않아요.
  • 모든 입력에는 보이는 라벨을 달아요. 라벨은 동사 없이 짧은 명사로 써요. (예: "설명 추가" 가 아니라 "설명")
  • placeholder 로 중요한 정보를 대신하지 않아요. 예시와 형식은 도움말에 둬요.

필수 필드

  • 필수 필드가 하나라도 있으면 "필수 항목은 별표(*)로 표시돼요" 같은 안내를 설명 뒤에 둬요.
  • 필수 필드는 라벨 뒤에 빨간 별표로 표시해요. 별표만으로 알리지 말고 안내 문구를 함께 둬요.
Do· 필수 안내 문구
폼 위쪽에 별표의 의미를 알려줘요.
Don't· 별표만 표시
별표의 뜻을 설명하지 않으면 사용자가 추측해야 해요.

버튼

  • 주요 액션은 primary 버튼 하나만 둬요. 필요할 때만 보조 버튼을 추가하고, 취소는 subtle 이나 링크 버튼으로 둬요.
  • 버튼 라벨은 구체적인 동작으로 써요. 제목이 "이슈 만들기" 라면 버튼도 "만들기" 처럼 같은 동사를 써요.
  • 초기화 버튼이나 여러 액션 버튼을 한 푸터에 몰아 두지 않아요.
  • 제출 중에는 스피너 등으로 진행 중임을 알려줘요.

Accessibility

  • 첫 번째 필드에 포커스를 두면 키보드 탐색 순서가 자연스러워요.
  • Field 는 라벨을 htmlFor 로, 메시지를 aria-describedby 로, 오류를 aria-invalid 로 입력에 연결해요. 메시지는 aria-live="polite" 영역 안에 있어 스크린 리더가 읽어 줘요.
  • 필수 별표는 aria-hidden 이고, 필수 여부는 입력의 required / aria-required 로 전달돼요.
  • 필수 값이 비어 있다고 제출 버튼을 비활성으로 만들지 말고, 제출했을 때 무엇이 필요한지 알려줘요.
  • 표준 autoComplete 값과 알맞은 type(email, tel 등)을 써서 입력을 줄이고 모바일 키보드를 맞춰요.
  • 제출할 때 오류가 있으면 첫 번째 오류 필드로 포커스가 이동해요.

Props

Form

Prop

Type

Field

Prop

Type

Layout

Prop

Type

CharacterCounter

Prop

Type

On this page