본문으로 건너뛰기

폼

입력 컴포넌트(Input · Textarea · Field), 라벨과 입력을 배치하는 컴포넌트, 입력 클래스입니다.

입력은 파인 칸입니다. 흰 면에 컨트롤 경계(바닥 위에서도 3:1)와 위쪽 안쪽 그늘이 있습니다. 손을 올리면 경계가 짙어지고, 포커스는 2px 링을 1px 띄워 그립니다. 오류(aria-invalid)는 빨간 경계이고, 색만이 아니라 Field 의 오류 아이콘과 문장이 함께 말합니다.

읽기 전용은 그늘 없는 파인 면에 본문색 글자라 복사할 값이 읽힙니다. 비활성은 투명도를 낮추지 않고 파인 면과 흐린 글자로 바꿉니다. select 는 네이티브 요소를 써서 FormData · 서버 액션과 바로 연결되고, 꺾쇠는 CSS 가 그립니다.

Input · Textarea 는 inputClass · inputSmClass 를 그대로 씁니다. 모양은 요소의 속성(aria-invalid · readonly · disabled)을 보고 CSS 가 고르므로 클래스 상수만 붙인 입력도 같은 모양입니다. textarea 는 클래스가 같아도 최소 88px 로 늘어납니다.

import
import { Field, Input, Textarea, NativeSelect } from "@uyoolabs/ui/ui";
쓰는 경우
라벨 · 도움말 · 오류가 붙은 입력은 Field 로 묶습니다. 설정 · 생성 화면처럼 라벨을 왼쪽 열에 두는 배치는 FormRow, 맨 아래 제출 버튼과 오류 요약은 FormField 를 씁니다.
검증 시점
입력하는 동안에는 검사하지 않고 칸을 떠날 때 검사합니다. 오류가 난 뒤 고치는 동안에는 맞는 값이 되는 즉시 오류를 지웁니다. 제출할 때는 FormField 가 오류를 한 번에 알립니다.
쓰지 않는 경우
필터 영역이나 표 행 안의 입력에는 FormRow 없이 inputSmClass 만 씁니다. 값 하나를 고르는 입력에 커스텀 드롭다운을 만들지 않고 NativeSelect 를 씁니다. 오류를 빨간 경계만으로 알리지 않습니다(Field 의 error 문장과 함께).
폐기 예고
FormRow · FormField 는 v2.x 에서 지웁니다. 왼쪽 라벨 배치는 Field 로, 제출 영역 · 오류 요약은 따로 나뉜 컴포넌트로 옮깁니다. 2.0 에서는 모양만 카톤으로 바뀌고 동작은 같습니다.

Input · Textarea

size 는 sm · md(기본값)입니다. invalid 를 주면 aria-invalid 가 붙습니다.

Field

라벨 · 컨트롤 · 도움말 · 오류 한 묶음입니다. id · htmlFor · aria-describedby 를 대신 잇습니다.

주소를 고친 뒤 칸을 떠나 보세요. 오류는 칸을 떠날 때 나타나고, 고치는 즉시 사라집니다.

주소에 쓰입니다. 나중에 바꿀 수 있습니다.

팀 이름은 2자 이상입니다. 한 글자 이상 더 씁니다.

API 호출에 씁니다.

import
import { Field, Input, Textarea } from "@uyoolabs/ui/ui";
children
컨트롤을 그리는 함수입니다. 받은 id · aria-describedby · aria-invalid · aria-required 를 컨트롤에 펼칩니다.
error
무엇이 문제인지와 어떻게 고치는지를 한 문장으로 씁니다. 아이콘과 함께 보이고 aria-describedby 로 연결됩니다. '잘못된 입력입니다' 같은 문장은 쓰지 않습니다.
required
라벨 옆에 * 를 보이고 aria-required 를 답니다.
announce
오류를 바로 읽어 줍니다(role=alert). 기본값은 꺼져 있습니다. 칸을 떠날 때 켜진 알림은 다음 칸의 라벨을 가로막기 때문입니다. 제출 없이 서버 확인만으로 오류가 생기는 칸에만 켭니다.

props

소스의 타입과 JSDoc 에서 생성한 표입니다. 컴포넌트를 고치면 pnpm gen 으로 다시 만듭니다.

Input

prop타입기본값설명
size"sm" | "md""md"sm 은 필터 바 · 표 행 안의 작은 입력(28px, inputSmClass), md 는 기본(36px, inputClass). 네이티브 size(글자 수 폭)는 받지 않는다
invalidboolean—aria-invalid 를 달아 빨간 경계를 그린다. 오류 문장은 Field 의 error 로 연결한다

이 밖에 <input> props(size 제외)를 그대로 받습니다.

Textarea

prop타입기본값설명
invalidboolean—aria-invalid 를 달아 빨간 경계를 그린다

이 밖에 <textarea> props를 그대로 받습니다.

Field

prop타입기본값설명
label필수ReactNode—
hintReactNode—무엇을 넣는지 · 어디에 쓰이는지. 컨트롤 아래에 두고 aria-describedby 로 연결한다
errorReactNode—무엇이 문제인지 + 어떻게 고치는지 한 문장(스펙 보드 C-Input). 있으면 aria-invalid 를 단다
requiredboolean—라벨 옆에 * 를 보이고 aria-required 를 단다. 네이티브 required 는 브라우저 말풍선이 오류 요약과 겹쳐 쓰지 않는다
announceboolean—오류가 생기는 즉시 읽어 준다(role="alert"). 기본값은 끈다. 스펙 보드는 칸을 떠날 때 검사하므로, alert 를 켜 두면 Tab 으로 다음 칸에 들어가는 순간 그 칸의 라벨 대신 앞 칸의 오류를 끼어들어 읽는다. 오류 안내는 제출할 때 오류 요약이 한 번에 맡는다. 제출 없이 서버 확인(주소 중복 등)만으로 오류가 생기는 칸에만 켠다.
count{ value: number; max: number }—글자 수. 힌트 오른쪽에 “3 / 40” 을 보이고 aria-describedby 로 잇는다. 넘으면 숫자만 오류 색 500 이 된다. 입력하는 동안 검사하지 않는다(C-Form 검증 시점). 넘은 것은 칸을 떠날 때 error 로 알린다
layout"top" | "start""top"라벨 자리. top(기본)은 칸 위, start 는 왼쪽 144px 열(칸이 많은 설정 화면, FormRow 대신). start 는 폼 폭 480 미만(uyoo-form 컨테이너, 없으면 화면 폭)에서 위로 접힌다
idstring—컨트롤 id. 주지 않으면 useId 로 만든다
classNamestring—
children필수(control: FieldControlProps) => ReactNode—컨트롤을 그리는 함수. cloneElement 대신 render-prop 을 고른 이유: - 검색 · 단위 · 복사 버튼이 붙은 입력처럼 컨트롤이 감싸져 있어도 props 가 정확히 그 입력에 간다. cloneElement 는 바깥 div 에 id 를 붙인다. - 받는 props 가 타입으로 드러나고, 어떤 컨트롤(Input · NativeSelect · textarea)이든 같은 방식이다.

키보드

키동작
Tab다음 칸으로 옮깁니다. 읽기 전용 칸은 포커스를 받고(값을 복사할 수 있게), 비활성 칸은 건너뜁니다.
Enter한 줄 입력에서는 폼을 제출합니다(브라우저 기본). 한 · 일 조합 중의 Enter 는 글자를 확정하는 키라 제출 · 추가로 처리하지 않습니다(isComposing). Textarea 에서는 줄을 바꿉니다.

Enter 와 한글 조합

한글 · 일본어를 조합하는 중에 누른 Enter 는 글자를 확정하는 키입니다. 제출 · 추가로 처리하지 않습니다.

Enter 로 더합니다. 한글을 조합하는 중에 누른 Enter 는 글자만 확정합니다.

결제정산

FormRow

라벨 · 입력 · 도움말(hint) 한 줄입니다.

화면에 보이는 이름입니다.

입력 클래스

inputClass · inputSmClass · selectClass · labelClass. 컴포넌트를 쓸 수 없는 자리에 붙이는 클래스 API 입니다.

FormField

폼 하단의 제출 영역입니다. 오류가 있으면 버튼 위에 빨간 틴트 상자로 표시됩니다. v2.x 에서 폐기 예정입니다.

전체 예시

서버 액션과 연결한 폼 전체 구성입니다.

화면에 보이는 이름입니다.

체크박스 · 라디오

브라우저 기본 파랑 대신 primary 컬러를 쓰고 크기는 16px 입니다. 클래스 없이 전역 스타일로 적용됩니다.

체크박스
라디오