Skip to content

NumberField

숫자만 담는 필드입니다. 셸은 픽셀 단위로 TextField의 것이고, 그 위에 스테핑과 범위 제한과 서식이 얹힙니다.

tsx
import { NumberField } from 'neba';

<NumberField label="좌석" defaultValue={3} min={1} max={20} />;

Props

Prop타입기본값설명
variant공통'solid' | 'outline' | 'text''outline'표면의 무게. TextField와 같은 셸입니다
size공통'xs' | 'sm' | 'md' | 'lg' | 'xl''md'높이와 타입 스케일. 스테퍼는 em이므로 숫자를 따라갑니다
color공통'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'의미론적 색 역할. 표면은 흰색이므로 가장자리·포커스 링·캐럿·스테퍼의 호버에 나타납니다
density공통'default' | 'compact''default'여백만 바꿉니다. 높이와 글자 크기는 그대로
elevation공통0 | 1 | 2 | 30그림자 깊이. 0은 그림자 없음
valuenumber | null값. null이 비어 있음입니다 — 파싱해야 하는 문자열이 아닙니다
defaultValuenumber초기 값
onValueChange(value: number | null) => void값이 바뀔 때마다 — 타이핑, 스테핑, 휠
onValueCommitted(value: number | null) => void값이 자리를 잡을 때. 타이핑 후 blur, 누르기를 뗄 때
minnumber범위의 시작. 스테핑은 여기서 멈춥니다
maxnumber범위의 끝
stepnumber | 'any'1한 걸음의 크기. any는 step 검증을 끕니다
largeStepnumber10Shift를 누른 채의 한 걸음
smallStepnumber0.1Alt를 누른 채의 한 걸음
snapOnStepbooleanfalse스테핑이 step의 배수에 붙는지
allowWheelScrubbooleanfalse포커스된 채 호버 중일 때 휠이 값을 바꾸는지. 포인터 아래에서 스크롤되는 페이지와 바뀌는 필드는 같은 제스처이고, 의도된 것은 하나뿐입니다
formatIntl.NumberFormatOptions숫자를 어떻게 쓸지 — 통화, 백분율, 소수 자릿수. 필드는 $1,240을 보여 주고 값으로는 1240을 보고합니다
localeIntl.LocalesArgument어느 로케일로 쓰고 읽을지. 기본은 런타임의 것
steppers'end' | 'split' | 'none''end'스테퍼가 앉는 자리. split은 숫자 양옆, none은 버튼 없음
labelReactNode컨트롤과 연결되는 라벨. Base UI Field가 묶어 줍니다
descriptionReactNode보조 설명
errorReactNode오류 메시지. 값이 있으면 invalid 상태도 함께 켜지고 색 계열이 danger로 넘어갑니다
invalidboolean!!error메시지 없이 invalid만 켭니다. 외부 폼 라이브러리가 유효성을 가질 때
startIconReactNode숫자 앞에 놓이는 내용 — 통화 기호, 단위
endIconReactNode숫자 뒤, 스테퍼 앞에 놓이는 내용
fullWidthbooleanfalse컨테이너 너비만큼 확장
incrementLabelstring'Increase'증가 버튼의 접근성 이름
decrementLabelstring'Decrease'감소 버튼의 접근성 이름
namestring폼 제출 시의 필드 이름
readOnlybooleanfalse값은 보이지만 바꿀 수 없음. 색과 가장자리는 유지한 채 채도만 빠집니다
disabledbooleanfalse사용 불가. 색 계열을 버리고 중립 회색이 됩니다

<input type="number">가 아닙니다

네이티브 숫자 입력은 브라우저마다 다른 곳의 모서리를 깎고, 로케일을 무시하고, 페이지 스크롤과 싸우는 휠 제스처를 제공하고, 필드에 말이 안 되는 것이 들어 있으면 빈 string을 건네줍니다. 이 컴포넌트는 지킬 만한 것만 지키고 각각에 답합니다.

  • valuenumber | null이고, null이 비어 있음입니다. 파싱해야 하는 문자열이 아닙니다.
  • formatIntl.NumberFormatOptions입니다. 필드는 $1,240이나 7.5%를 보여 주면서 값으로는 12400.075를 보고합니다.
  • 방향키는 step만큼, Shift는 largeStep만큼, Alt는 smallStep만큼 움직입니다.
  • 휠은 allowWheelScrub이 그러라고 하지 않는 한 아무것도 하지 않습니다. 포인터 아래에서 스크롤되는 페이지와 포인터 아래에서 바뀌는 필드는 같은 제스처이고, 의도된 것은 둘 중 하나뿐입니다.

예시

스테퍼

end는 모두가 봐 온 스피너입니다. split은 숫자의 양옆에 마이너스와 플러스를 두는데, 타이핑하기보다 톡톡 건드려 맞추는 수량을 위한 것입니다. none은 버튼만 빼고 나머지는 그대로 둡니다.

절반 높이의 셰브런을 세로로 쌓는 형태는 일부러 두지 않았습니다. xs에서는 화살표 하나가 3픽셀도 되지 않고, 그 정도로 작은 표적은 아무도 맞히지 못하는 표적입니다.

서식

필드가 무엇을 보여 주든 value는 순수한 숫자로 남습니다.

Variant

크기

스테퍼는 em으로 크기가 정해지므로 자기만의 사다리를 갖는 대신 숫자를 따라갑니다 — 그리고 필드는 같은 size의 Button·TextField·Select와 같은 줄에 섭니다.

상태

읽기 전용은 스테퍼를 비활성화하는 대신 아예 치웁니다. 보이는데 누를 때마다 거절하는 버튼은 없는 버튼보다 나쁩니다. 숫자는 여전히 선택할 수 있습니다 — 읽기 전용 필드도 복사해 가는 대상이기 때문입니다.

접근성

  • 파싱, 범위 제한, 스테퍼의 길게 누르기 반복은 모두 Base UI가 담당합니다.
  • 보이는 것은 <input type="number">가 아니라 inputmode="numeric"과 _Number field_라는 aria-roledescription을 단 텍스트 입력입니다. 그 옆에는 min·max·step을 들고 있는 숨은 <input type="number">가 있고, 폼이 제출하고 브라우저가 검증하는 것은 이쪽입니다. 둘을 갈라 놓은 덕분에 보이는 필드는 브라우저가 파싱을 거부하는 일 없이 $1,240을 보여 줄 수 있습니다.
  • label이 접근성 이름이 되고, 스테퍼의 이름은 incrementLabeldecrementLabel이 짓습니다. 스테퍼는 탭 순서에서 빠져 있는데, 필드 자체의 방향키가 이미 그 일을 하기 때문입니다.
  • min이나 max에 닿은 스테퍼는 disabled입니다 — 흐려지는 대신, 라이브러리의 다른 모든 비활성 컨트롤과 같이 색 계열이 바뀝니다.

Released under the MIT License