숫자 입력

숫자 입력 (InputNumber)

숫자 값만 입력받는 입력 상자 컴포넌트예요. 최소·최대 범위, 증감 단계, 포맷터 등을 지원해요.

출처: 문서

본문

언제 사용하나요 (When To Use)

  • 숫자 값을 입력받아야 할 때 사용해요.

예시 (Examples)

기본 (Basic)

숫자 전용 입력 상자예요.

import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber } from 'antd';

const onChange: InputNumberProps['onChange'] = (value) => {
  console.log('changed', value);
};

const App: React.FC = () => <InputNumber min={1} max={10} defaultValue={3} onChange={onChange} />;

export default App;

크기 (Sizes)

숫자 입력 상자에는 세 가지 크기가 있어요. 기본 크기는 32px이며, 추가로 large(40px)와 small(24px)이 있어요.

import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber, Space } from 'antd';

const onChange: InputNumberProps['onChange'] = (value) => {
  console.log('changed', value);
};

const App: React.FC = () => (
  <Space wrap>
    <InputNumber size="large" min={1} max={100000} defaultValue={3} onChange={onChange} />
    <InputNumber min={1} max={100000} defaultValue={3} onChange={onChange} />
    <InputNumber size="small" min={1} max={100000} defaultValue={3} onChange={onChange} />
  </Space>
);

export default App;

비활성화 (Disabled)

버튼을 클릭해 사용 가능 상태와 비활성 상태를 전환해요.

import React, { useState } from 'react';
import { Button, InputNumber } from 'antd';

const App: React.FC = () => {
  const [disabled, setDisabled] = useState(true);

  const toggle = () => {
    setDisabled(!disabled);
  };

  return (
    <>
      <InputNumber min={1} max={10} disabled={disabled} defaultValue={3} />
      <div style={{ marginTop: 20 }}>
        <Button onClick={toggle} type="primary">
          Toggle disabled
        </Button>
      </div>
    </>
  );
};

export default App;

고정밀 소수 (High precision decimals)

stringMode를 사용하면 고정밀 소수를 지원해요. onChange가 대신 문자열 값을 반환해요. 브라우저가 BigInt를 지원하지 않으면 BigInt의 polyfill이 필요해요.

import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber } from 'antd';

const onChange: InputNumberProps['onChange'] = (value) => {
  console.log('changed', value);
};

const App: React.FC = () => (
  <InputNumber<string>
    style={{ width: 200 }}
    defaultValue="1"
    min="0"
    max="10"
    step="0.00000000000001"
    onChange={onChange}
    stringMode
  />
);

export default App;

포맷터 (Formatter)

formatter로 값을 상황에 맞게 표시하고, 보통 parser도 함께 사용해요.

다음은 Intl.NumberFormat 기반의 InputNumber 구현이에요: https://codesandbox.io/s/currency-wrapper-antd-input-3ynzo

import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber, Space } from 'antd';

const onChange: InputNumberProps['onChange'] = (value) => {
  console.log('changed', value);
};

const formatter: InputNumberProps<number>['formatter'] = (value) => {
  const [start, end] = `${value}`.split('.') || [];
  const v = `${start}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
  return `$ ${end ? `${v}.${end}` : `${v}`}`;
};

const App: React.FC = () => (
  <Space>
    <InputNumber<number>
      defaultValue={1000}
      formatter={formatter}
      parser={(value) => value?.replace(/\$\s?|(,*)/g, '') as unknown as number}
      onChange={onChange}
    />
    <InputNumber<number>
      defaultValue={100}
      min={0}
      max={100}
      formatter={(value) => `${value}%`}
      parser={(value) => value?.replace('%', '') as unknown as number}
      onChange={onChange}
    />
  </Space>
);

export default App;

키보드 (Keyboard)

keyboard로 키보드 동작을 제어해요.

import React, { useState } from 'react';
import { Checkbox, InputNumber, Space } from 'antd';

const App: React.FC = () => {
  const [keyboard, setKeyboard] = useState(true);

  return (
    <Space>
      <InputNumber min={1} max={10} keyboard={keyboard} defaultValue={3} />
      <Checkbox
        onChange={() => {
          setKeyboard(!keyboard);
        }}
        checked={keyboard}
      >
        Toggle keyboard
      </Checkbox>
    </Space>
  );
};

export default App;

휠 (Wheel)

마우스 휠로 제어해요.

import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber } from 'antd';

const onChange: InputNumberProps['onChange'] = (value) => {
  console.log('changed', value);
};

const onStep: InputNumberProps['onStep'] = (value, info) => {
  console.log('onStep', value, info);
};

const App: React.FC = () => (
  <InputNumber
    min={1}
    max={10}
    defaultValue={3}
    onChange={onChange}
    onStep={onStep}
    changeOnWheel
  />
);

export default App;

변형 (Variants)

InputNumber의 변형에는 네 가지가 있어요. outlined, filled, borderless, underlined.

import React from 'react';
import { Flex, InputNumber } from 'antd';

const App: React.FC = () => (
  <Flex vertical gap={12}>
    <InputNumber placeholder="Outlined" style={{ width: 200 }} />
    <InputNumber placeholder="Filled" variant="filled" style={{ width: 200 }} />
    <InputNumber placeholder="Borderless" variant="borderless" style={{ width: 200 }} />
    <InputNumber placeholder="Underlined" variant="underlined" style={{ width: 200 }} />
  </Flex>
);

export default App;

스피너 (Spinner)

숫자 스피너 예시예요.

import React from 'react';
import type { InputNumberProps } from 'antd';
import { Flex, InputNumber } from 'antd';

const onChange: InputNumberProps['onChange'] = (value) => {
  console.log('changed', value);
};

const sharedProps = {
  mode: 'spinner' as const,
  min: 1,
  max: 10,
  defaultValue: 3,
  onChange,
  style: { width: 150 },
};

const App: React.FC = () => (
  <Flex vertical gap="medium">
    <InputNumber {...sharedProps} placeholder="Outlined" />
    <InputNumber {...sharedProps} variant="filled" placeholder="Filled" />
  </Flex>
);

export default App;

범위 밖 (Out of range)

제어(control)로 value가 범위를 벗어나면 경고 스타일을 보여 줘요.

import React, { useState } from 'react';
import { Button, InputNumber, Space } from 'antd';

const App: React.FC = () => {
  const [value, setValue] = useState<string | number | null>('99');

  return (
    <Space>
      <InputNumber min={1} max={10} value={value} onChange={setValue} />
      <Button
        type="primary"
        onClick={() => {
          setValue(99);
        }}
      >
        Reset
      </Button>
    </Space>
  );
};

export default App;

접두사 / 접미사 (Prefix / Suffix)

입력 안쪽에 접두사나 접미사를 추가해요.

import React from 'react';
import { UserOutlined } from '@ant-design/icons';
import { Flex, InputNumber, Space } from 'antd';

const App: React.FC = () => (
  <Flex vertical gap="medium">
    <InputNumber prefix="¥" style={{ width: '100%' }} />

    <Space.Compact block>
      <Space.Addon>
        <UserOutlined />
      </Space.Addon>
      <InputNumber prefix="¥" style={{ width: '100%' }} />
    </Space.Compact>

    <InputNumber prefix="¥" disabled style={{ width: '100%' }} />

    <InputNumber suffix="RMB" style={{ width: '100%' }} />
  </Flex>
);

export default App;

상태 (Status)

status로 InputNumber에 상태를 추가해요. error 또는 warning이 될 수 있어요.

import React from 'react';
import ClockCircleOutlined from '@ant-design/icons/ClockCircleOutlined';
import { InputNumber, Space } from 'antd';

const App: React.FC = () => (
  <Space vertical style={{ width: '100%' }}>
    <InputNumber status="error" style={{ width: '100%' }} />
    <InputNumber status="warning" style={{ width: '100%' }} />
    <InputNumber status="error" style={{ width: '100%' }} prefix={<ClockCircleOutlined />} />
    <InputNumber status="warning" style={{ width: '100%' }} prefix={<ClockCircleOutlined />} />
  </Space>
);

export default App;

포커스 (Focus)

추가 옵션과 함께 포커스를 맞춰요.

import React, { useRef } from 'react';
import type { GetRef } from 'antd';
import { Button, InputNumber, Space } from 'antd';

type InputNumberRef = GetRef<typeof InputNumber>;

const App: React.FC = () => {
  const inputRef = useRef<InputNumberRef>(null);
  return (
    <Space vertical style={{ width: '100%' }}>
      <Space wrap>
        <Button
          onClick={() => {
            inputRef.current?.focus({ cursor: 'start' });
          }}
        >
          Focus at first
        </Button>
        <Button
          onClick={() => {
            inputRef.current?.focus({ cursor: 'end' });
          }}
        >
          Focus at last
        </Button>
        <Button
          onClick={() => {
            inputRef.current?.focus({ cursor: 'all' });
          }}
        >
          Focus to select all
        </Button>
        <Button
          onClick={() => {
            inputRef.current?.focus({ preventScroll: true });
          }}
        >
          Focus prevent scroll
        </Button>
      </Space>
      <InputNumber style={{ width: '100%' }} defaultValue={999} ref={inputRef} />
    </Space>
  );
};

export default App;

시맨틱 DOM 스타일링 (Custom semantic dom styling)

classNames와 styles로 객체나 함수를 전달해 InputNumber의 시맨틱 DOM 스타일을 커스터마이즈할 수 있어요.

import React from 'react';
import { Flex, InputNumber } from 'antd';
import type { GetProp, InputNumberProps } from 'antd';
import { createStyles } from 'antd-style';

const useStyle = createStyles(({ token }) => ({
  root: {
    border: `${token.lineWidth}px ${token.lineType} ${token.colorPrimary}`,
    borderRadius: token.borderRadiusLG,
    width: 200,
  },
}));

const stylesObject: InputNumberProps['styles'] = {
  input: {
    fontSize: 14,
  },
};

const stylesFn: InputNumberProps['styles'] = ({
  props,
}): GetProp<InputNumberProps, 'styles', 'Return'> => {
  if (props.size === 'large') {
    return {
      root: {
        backgroundColor: 'rgba(250,250,250, 0.5)',
        borderColor: '#722ed1',
      },
    };
  }
  return {};
};

const App: React.FC = () => {
  const { styles: classNames } = useStyle();
  const sharedProps: InputNumberProps = {
    classNames,
  };
  return (
    <Flex vertical gap="medium">
      <InputNumber {...sharedProps} styles={stylesObject} placeholder="Object" />
      <InputNumber {...sharedProps} styles={stylesFn} placeholder="Function" size="large" />
    </Flex>
  );
};

export default App;

API

공통 props는 Common props를 참고해요.

속성 (Property) 설명 (Description) 타입 (Type) 기본값 (Default) 버전 (Version) 글로벌 설정
addonAfter 입력 필드 뒤(오른쪽)에 표시되는 라벨 텍스트예요. Space.Compact를 대신 사용해 주세요. ReactNode - 4.17.0 ×
addonBefore 입력 필드 앞(왼쪽)에 표시되는 라벨 텍스트예요. Space.Compact를 대신 사용해 주세요. ReactNode - 4.17.0 ×
changeOnBlur blur 시 onChange를 트리거해요. 예: blur로 값을 범위 안으로 리셋. boolean true 5.11.0 ×
changeOnWheel 마우스 휠로 제어를 허용해요. boolean - 5.14.0 ×
classNames 컴포넌트 내부의 각 시맨틱 구조에 대한 class를 지정해요. 객체 또는 함수를 지원해요. Record<SemanticDOM, string> | (info: { props })=> Record<SemanticDOM, string> - 6.0.0 6.0.0
controls +- 컨트롤을 표시할지, 또는 커스텀 화살표 아이콘을 설정할지 여부 boolean | { upIcon?: React.ReactNode; downIcon?: React.ReactNode; } - ×
decimalSeparator 소수점 구분자 string - - ×
placeholder 플레이스홀더 string - ×
defaultValue 초기 값 number - - ×
disabled 입력 비활성화 여부 boolean false - ×
formatter 표시되는 값의 형식을 지정해요. function(value: number | string, info: { userTyping: boolean, input: string }): string - ×
keyboard 키보드 동작 활성화 여부 boolean true ×
max 최대 값 number Number.MAX_SAFE_INTEGER - ×
min 최소 값 number Number.MIN_SAFE_INTEGER - ×
parser formatter에서 추출할 값을 지정해요. function(string): number - - ×
precision 입력 값의 정밀도예요. formatter 설정 시 formatter를 사용해요. number - - ×
readOnly 입력이 읽기 전용인지 여부 boolean false - ×
status 검증 상태 설정 'error' | 'warning' - ×
styles 컴포넌트 내부의 각 시맨틱 구조에 대한 인라인 스타일을 지정해요. 객체 또는 함수를 지원해요. Record<SemanticDOM, CSSProperties> | (info: { props })=> Record<SemanticDOM, CSSProperties> - 6.0.0 6.0.0
prefix Input의 접두사 아이콘 ReactNode - ×
suffix Input의 접미사 아이콘 ReactNode - 5.20.0 ×
size 입력 상자의 높이 large | medium | small - - ×
step 현재 값이 증가하거나 감소하는 단위예요. 정수 또는 소수일 수 있어요. number | string 1 - ×
stringMode 값을 문자열로 설정해 고정밀 소수를 지원해요. onChange가 문자열 값을 반환해요. boolean false 4.13.0 ×
mode 입력 또는 스피너 표시 'input' | 'spinner' 'input' ×
value 컴포넌트의 현재 값 number - - ×
variant Input의 변형 outlined | borderless | filled | underlined outlined 5.13.0 | underlined: 5.24.0 5.19.0
onChange 값이 변경될 때 트리거되는 콜백 function(value: number | string | null) - - ×
onPressEnter Enter 키를 누를 때 트리거되는 콜백 함수 function(e) - - ×
onStep 위·아래 버튼 / 키보드 / 휠을 클릭할 때 트리거되는 콜백 함수 (value: number, info: { offset: number, type: 'up' | 'down', emitter: 'handler' | 'keydown' | 'wheel' }) => void - - ×
bordered 테두리 스타일 여부예요. variant를 대신 사용해 주세요. boolean true - ×

Ref

이름 (Name) 설명 (Description) 타입 (Type) 버전 (Version)
blur() 포커스 제거 -
focus() 포커스 획득 (option?: { preventScroll?: boolean, cursor?: 'start' | 'end' | 'all' }) cursor - 5.22.0
nativeElement 네이티브 DOM 요소 - 5.17.3

시맨틱 DOM (Semantic DOM)

시맨틱 DOM 구조는 https://ant.design/components/input-number/semantic.md 에서 확인할 수 있어요.

디자인 토큰 (Design Token)

컴포넌트 토큰 (InputNumber) (Component Token)

토큰 이름 (Token Name) 설명 (Description) 타입 (Type) 기본값 (Default Value)
activeBg 입력 상자가 활성화될 때 배경색 string #ffffff
activeBorderColor 활성 테두리 색 string #1677ff
activeShadow 활성 시 box-shadow string 0 0 0 2px rgba(5,145,255,0.1)
addonBg addon의 배경색 string rgba(0,0,0,0.02)
controlWidth 입력 너비 number 90
errorActiveShadow 오류 상태에서 활성 시 box-shadow string 0 0 0 2px rgba(255,38,5,0.06)
filledHandleBg filled 변형에서 핸들의 배경색 string #f0f0f0
handleActiveBg 핸들의 활성 배경색 string rgba(0,0,0,0.02)
handleBg 핸들의 배경색 string #ffffff
handleBorderColor 핸들의 테두리 색 string #d9d9d9
handleFontSize 컨트롤 버튼의 아이콘 크기 number 7
handleHoverColor 핸들의 hover 색 string #1677ff
handleVisible 핸들 표시 여부 true | "auto" auto
handleWidth 컨트롤 버튼의 너비 number 22
hoverBg 입력 상자를 hover할 때 배경색 string #ffffff
hoverBorderColor hover 테두리 색 string #4096ff
inputFontSize 글자 크기 number 14
inputFontSizeLG 큰 글자 크기 number 16
inputFontSizeSM 작은 글자 크기 number 14
paddingBlock 입력의 세로 패딩 number 4
paddingBlockLG 큰 입력의 세로 패딩 number 7
paddingBlockSM 작은 입력의 세로 패딩 number 0
paddingInline 입력의 가로 패딩 number 11
paddingInlineLG 큰 입력의 가로 패딩 number 11
paddingInlineSM 작은 입력의 가로 패딩 number 7
warningActiveShadow 경고 상태에서 활성 시 box-shadow string 0 0 0 2px rgba(255,215,5,0.1)

글로벌 토큰 (Global Token)

토큰 이름 (Token Name) 설명 (Description) 타입 (Type) 기본값 (Default Value)
borderRadius 기본 컴포넌트의 테두리 반경 number
borderRadiusLG LG 크기 테두리 반경이에요. Card, Modal 등 큰 테두리 반경을 가진 컴포넌트에 사용돼요. number
borderRadiusSM SM 크기 테두리 반경이에요. Button, Input, Select 등 작은 크기의 입력 컴포넌트에 사용돼요. number
colorBgContainer 컨테이너 배경색이에요. 기본 버튼, 입력 상자 등. colorBgElevated와 혼동하지 마세요. string
colorBgContainerDisabled 비활성 상태에서 컨테이너의 배경색을 제어해요. string
colorBorder 기본 테두리 색이에요. 폼 구분선, 카드 구분선처럼 서로 다른 요소를 구분하는 데 사용돼요. string
colorBorderDisabled 비활성 상태의 요소 테두리 색을 제어해요. string
colorError 오류 Button, 오류 Result 컴포넌트 등 작업 실패의 시각적 요소를 나타내는 데 사용돼요. string
colorErrorAffix 오류 상태에서 폼 컨트롤 접두사/접미사 색을 제어해요. string
colorErrorBg 오류 상태의 배경색 string
colorErrorBgHover 오류 상태의 hover 배경색 string
colorErrorBorderHover 오류 상태의 hover 테두리 색 string
colorErrorText 오류 색에서 텍스트의 기본 상태 string
colorFillSecondary 2단계 fill 색으로 Rate, Skeleton 등 요소의 모양을 더 선명하게 나타낼 수 있어요. Table 등에서 3단계 fill 색의 Hover 상태로도 쓰여요. string
colorFillTertiary 3단계 fill 색으로 Slider, Segmented 등 요소의 모양을 나타내는 데 사용돼요. 강조 요구가 없다면 3단계 fill 색을 기본 fill로 쓰는 걸 권장해요. string
colorIcon 약한 동작이에요. allowClear나 Alert 닫기 버튼 같은 것. string
colorText W3C 표준을 따르는 기본 텍스트 색이에요. 가장 어두운 중성색이기도 해요. string
colorTextDisabled 비활성 상태의 텍스트 색을 제어해요. string
colorTextPlaceholder 플레이스홀더 텍스트 색을 제어해요. string
colorWarning Notification, Alert 등 경고를 나타내는 map 토큰에 사용돼요. Alert나 Input 같은 컨트롤 컴포넌트도 이 map 토큰을 사용해요. string
colorWarningAffix 경고 상태에서 폼 컨트롤 접두사/접미사 색을 제어해요. string
colorWarningBg 경고 상태의 배경색 string
colorWarningBgHover 경고 상태의 hover 배경색 string
colorWarningBorderHover 경고 상태의 hover 테두리 색 string
colorWarningText 경고 색에서 텍스트의 기본 상태 string
fontFamily Ant Design의 글꼴은 시스템의 기본 인터페이스 글꼴을 우선시하고, 화면 표시에 적합한 대체 글꼴 라이브러리를 제공해 플랫폼과 브라우저에 따라 가독성을 유지하며 친근하고 안정적이며 전문적인 특성을 반영해요. string
fontSize 디자인 시스템에서 가장 널리 쓰이는 글자 크기로, 여기서 텍스트 그라데이션이 파생돼요. number
lineHeight 텍스트의 줄 높이예요. number
lineHeightLG 큰 텍스트의 줄 높이예요. number
lineType 기본 컴포넌트의 테두리 스타일 string
lineWidth 기본 컴포넌트의 테두리 두께 number
motionDurationMid 동작 속도, 중간 속도예요. 중간 요소의 애니메이션 상호작용에 사용돼요. string
paddingXXS 요소의 아주 작은 패딩을 제어해요. number

참고 (Notes)

이슈 #21158, #17344, #9421과 입력에 관한 문서에 따라, 커뮤니티는 <Input /> 속성에 type="number"를 네이티브로 포함하는 것을 지원하지 않는 것으로 보여요. 필요하면 자유롭게 포함하되, 파워 유저가 클라이언트 측 검증을 편집할 수 있으므로 서버 측 검증을 사용하는 것을 강력히 권장해요.

FAQ

제어(control)에서 value가 min이나 max를 초과할 수 있는 이유는 무엇인가요? {#faq-controlled-range}

개발자가 제어 상태에서 데이터를 직접 관리해요. InputNumber가 표시 값을 바꾸면 데이터가 어긋날 수 있어요. 폼에서 사용할 때도 잠재적인 데이터 문제를 일으킬 수 있어요.

min이나 max를 동적으로 변경해 value가 범위 밖이 되는데 onChange가 트리거되지 않는 이유는 무엇인가요? {#faq-dynamic-range-change}

onChange는 사용자 트리거 이벤트예요. 자동 트리거되면 폼 라이브러리가 데이터 수정 소스를 감지하지 못해요.

왜 onBlur 같은 이벤트에서 올바른 값을 얻을 수 없나요? {#faq-onblur-value}

InputNumber의 값은 내부 로직으로 감싸져 있어요. onBlur 등에서 얻는 event.target.value는 DOM 요소의 value이지 InputNumber의 실제 값이 아니에요. 예를 들어 formatter나 decimalSeparator로 표시 형식을 바꾸면 DOM에서 포맷된 문자열을 얻게 돼요. 항상 onChange로 현재 값을 얻어야 해요.

changeOnWheel이 마우스 스크롤 휠이 값을 바꾸는지 제어하지 못하는 이유는 무엇인가요? {#faq-change-on-wheel}

type 속성 사용은 더 이상 권장되지 않아요.

InputNumber 컴포넌트는 input 요소의 모든 속성을 사용할 수 있고 결국 input 요소에 전달돼요. type='number'를 전달하면 이 속성도 input 요소에 추가되어 네이티브 동작(마우스 휠이 값을 바꾸는 것)을 활성화해요. 그래서 changeOnWheel이 마우스 휠이 값을 바꾸는지 제어할 수 없는 거예요.

더 알아보기 (Learn more)