TextField
한 줄 또는 여러 줄 텍스트 입력. 라벨·설명·오류가 하나의 컴포넌트로 묶여 있고, 연결은 Base UI의 Field가 맡습니다.
import { TextField } from 'neba';
<TextField label="이메일" value={email} onChange={(event) => setEmail(event.target.value)} />;Props
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| variant공통 | 'solid' | 'outline' | 'text' | 'outline' | 표면의 무게. solid도 색으로 채우지 않습니다 — 필드가 담는 것은 사용자 데이터입니다 |
| size공통 | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | 높이와 타입 스케일. Button과 같은 높이라서 한 줄에 섞어 놓아도 기준선이 맞습니다 |
| color공통 | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'primary' | 의미론적 색 역할. 표면은 흰색이므로 가장자리와 포커스 링, 캐럿에만 나타납니다 |
| density공통 | 'default' | 'compact' | 'default' | 여백만 바꿉니다. 높이와 글자 크기는 그대로 |
| elevation공통 | 0 | 1 | 2 | 3 | 0 | 그림자 깊이. 필드는 떠 있는 표면이 아니므로 거의 올리지 않습니다 |
| label | ReactNode | — | 컨트롤 위 라벨. Base UI Field로 연결됩니다 |
| description | ReactNode | — | 컨트롤 아래 보조 설명 |
| error | ReactNode | — | 컨트롤 아래 오류 메시지. 값이 있으면 invalid 상태도 함께 켜집니다 |
| invalid | boolean | !!error | 메시지 없이 invalid만 켭니다. 외부 폼 라이브러리가 유효성을 가질 때 |
| multiline | boolean | false | input 대신 textarea로 렌더링합니다. 나머지 축은 그대로 |
| rows | number | 3 | multiline일 때 보이는 줄 수 |
| resize | 'none' | 'vertical' | 'horizontal' | 'both' | 'vertical' | 사용자가 끌어서 크기를 바꿀 수 있는 방향. 가로는 폼의 열을 깨뜨립니다 |
| startIcon | ReactNode | — | 컨트롤 앞에 놓이는 내용 |
| endIcon | ReactNode | — | 컨트롤 뒤에 놓이는 내용 |
| loading | boolean | false | endIcon 자리에 스피너를 띄웁니다. 입력은 계속 가능합니다 |
| readOnly | boolean | false | 읽기 전용. 선택과 복사는 됩니다 |
| disabled | boolean | false | 사용 불가 |
| fullWidth | boolean | false | 컨테이너 너비만큼 확장 |
<input>의 네이티브 속성은 그대로 전달됩니다. color와 size는 위 표의 것과 이름이 겹쳐 제외되며, onChange는 multiline일 때 <textarea>도 받도록 넓혀져 있습니다.
예시
변형
solid도 색으로 채우지 않습니다. 필드가 담는 것은 사용자 데이터이고, 캐럿·선택 영역·플레이스홀더가 강조색 채움 위에서는 읽히지 않기 때문입니다. 색 계열은 가장자리와 포커스 링, 캐럿에 나타납니다.
시트 자체는 흰색이고, outline → solid → hover → 포커스로 갈수록 불투명해질 뿐 색이 진해지지는 않습니다. 색에 전체 규칙이 있습니다.
크기
Button과 높이가 같습니다. 툴바처럼 한 줄에 섞어 놓아도 기준선이 맞습니다.
여러 줄
multiline은 <textarea>로 바꿔 렌더링할 뿐, 나머지 축은 그대로입니다. rows={1}은 한 줄짜리 필드와 정확히 같은 높이입니다. 가로 리사이즈는 폼의 열을 깨뜨리므로 기본값이 세로뿐입니다.
아이콘과 진행 상태
loading은 endIcon 자리에 스피너를 놓고 aria-busy를 붙이지만, 입력은 막지 않습니다. 필드는 대개 방금 입력된 값 때문에 로딩 중이기 때문입니다.
상태
error에 내용이 있으면 필드 전체가 danger 계열로 넘어갑니다 — 가장자리, 포커스 링, 캐럿, 메시지가 한꺼번에 바뀝니다. 메시지 없이 무효 상태만 켜려면 invalid를 직접 주세요.
제어 컴포넌트
value와 onChange는 네이티브 그대로입니다.
접근성
- 라벨·설명·오류는 Base UI의 Field가
id와aria-describedby로 컨트롤에 연결합니다. - 떠오르는 라벨(floating label)은 제공하지 않습니다.
transform이 필요한데, 이 라이브러리의 컨트롤은 움직이지 않습니다. - 포커스 링은 컨트롤이 아니라 껍데기에 그려지므로, 아크릴 가장자리를 그대로 따라갑니다.
- 껍데기의 여백을 클릭해도 캐럿이 들어갑니다. 네이티브
<input>과 같은 동작입니다.