Input

Data Input

한 줄 텍스트를 입력받는 필드.

Usage

단일 라인 텍스트 입력. 이름·검색어·짧은 값

import

import

import { Input } from '@mildang/design-system/Input';

예제를 복사해 쓸 때 필요한 준비

@mildang/icons 를 따로 설치한다. DS 패키지에 아이콘 컴포넌트가 포함되지 않는다.

API Reference

Input Props

Prop

Type

Default

autoComplete

string

지정 안 함

autoFocus

boolean

지정 안 함

className

string

지정 안 함

endAdornment

ReactNode

지정 안 함

error

boolean

false

fullWidth

boolean

false

ghost

boolean

false

inputContainerClassName

string

지정 안 함

inputElementClassName

string

지정 안 함

multiple

boolean

지정 안 함

name

string

지정 안 함

onBlur

FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>

지정 안 함

onChange

ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>

지정 안 함

onFocus

FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>

지정 안 함

onInvalid

FormEventHandler<HTMLInputElement | HTMLTextAreaElement>

지정 안 함

onKeyDown

KeyboardEventHandler<HTMLInputElement | HTMLTextAreaElement>

지정 안 함

onKeyUp

KeyboardEventHandler<HTMLInputElement | HTMLTextAreaElement>

지정 안 함

size

"xs" | "sm" | "md" | "lg" | "xl"

md

startAdornment

ReactNode

지정 안 함

success

boolean

false

value

string

지정 안 함

warning

boolean

false

예제

기본 사용

placeholder 만 준 한 줄 입력 — 폼에 쓸 때는 Field 로 감싸 라벨과 오류 문구를 함께 붙입니다.

import type { ComponentProps } from 'react';
import { Input } from '@mildang/design-system/Input';

const STORY_DEFAULT_ARGS = { ...({}), ...({ placeholder: 'Enter text...', size: 'md', ghost: false }) } as ComponentProps<typeof Input>;

const InputDemoExampleRender = (args: ComponentProps<typeof Input>) => <Input {...args} />;

export default function InputDemoExample(props: Partial<ComponentProps<typeof Input>>) {
  const mergedProps = { ...STORY_DEFAULT_ARGS, ...props } as ComponentProps<typeof Input>;
  return InputDemoExampleRender(mergedProps);
}

크기

xs부터 xl까지 높이를 비교합니다. 한 폼 안에서는 크기를 섞지 않고 md 를 기준으로 둡니다.

import { Input } from '@mildang/design-system/Input';
import Eye from '@mildang/icons/react/eye';

const InputSizesExample = () => (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '12px', width: '320px' }}>
      {(['xs', 'sm', 'md', 'lg', 'xl'] as const).map((size) => (
        <div key={size} style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
          <span style={{ width: '24px', fontSize: '12px', color: '#666', flexShrink: 0 }}>{size}</span>
          <Input
            size={size}
            placeholder={`size=${size}`}
            startAdornment={<Eye />}
            endAdornment={<Eye />}
            fullWidth
          />
        </div>
      ))}
    </div>
  );

export default InputSizesExample;

상태

기본·오류·비활성을 나란히 둡니다. error 는 테두리만 바꾸므로 사유는 HelpText 로 함께 적습니다.

import { Text } from '@mildang/design-system/Text';
import { Input } from '@mildang/design-system/Input';
import Eye from '@mildang/icons/react/eye';

const InputDisabledExample = () => (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', width: '300px' }}>
      <div>
        <Text variant="title-sm-medium" mb="8px">
          Disabled (empty)
        </Text>
        <Input disabled placeholder="Placeholder" fullWidth />
      </div>
      <div>
        <Text variant="title-sm-medium" mb="8px">
          Disabled (with value)
        </Text>
        <Input disabled defaultValue="입력된 텍스트" fullWidth />
      </div>
      <div>
        <Text variant="title-sm-medium" mb="8px">
          Disabled + Adornments
        </Text>
        <Input
          disabled
          defaultValue="010-1234-5678"
          startAdornment={<Eye />}
          endAdornment={<Eye />}
          fullWidth
        />
      </div>
    </div>
  );

export default InputDisabledExample;

StatusGuide

import { Text } from '@mildang/design-system/Text';
import { Input } from '@mildang/design-system/Input';
import Eye from '@mildang/icons/react/eye';

const InputStatusGuideExample = () => (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', width: '500px' }}>
      <div>
        <Text variant="title-sm-medium" mb="8px">
          Inactive
        </Text>
        <Input placeholder="Default state" endAdornment={<Eye />} />
      </div>
      <div>
        <Text variant="title-sm-medium" mb="8px">
          Error
        </Text>
        <Input error placeholder="Error state" endAdornment={<Eye />} />
      </div>
      <div>
        <Text variant="title-sm-medium" mb="8px">
          Warning
        </Text>
        <Input warning placeholder="Warning state" endAdornment={<Eye />} />
      </div>
      <div>
        <Text variant="title-sm-medium" mb="8px">
          Success
        </Text>
        <Input success placeholder="Success state" endAdornment={<Eye />} />
      </div>
    </div>
  );

export default InputStatusGuideExample;

WithAdornments

import type { ComponentProps } from 'react';
import { Input } from '@mildang/design-system/Input';
import { Button } from '@mildang/design-system/Button';
import Eye from '@mildang/icons/react/eye';

const STORY_DEFAULT_ARGS = { ...({}), ...({ ghost: false }) } as ComponentProps<typeof Input>;

const InputWithAdornmentsExampleRender = (args: ComponentProps<typeof Input>) => {
    const inputProps = args;
    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16, width: 400 }}>
        <Input
          size="lg"
          defaultValue="010-1234-5678"
          endAdornment={
            <Button size="sm" variant="tertiary">
              인증
            </Button>
          }
          {...inputProps}
        />
        <Input startAdornment={<Eye />} size="lg" defaultValue="mildang@email.com" {...inputProps} />
        <Input endAdornment={<>Kg</>} startAdornment={<Eye />} placeholder="Enter text..." size="xl" />
        <Input endAdornment={<>Kg</>} startAdornment={<Eye />} placeholder="Enter text..." size="lg" />
        <Input endAdornment={<>Kg</>} startAdornment={<Eye />} placeholder="Enter text..." size="md" />
        <Input endAdornment={<>Kg</>} startAdornment={<Eye />} placeholder="Enter text..." size="sm" />
        <Input endAdornment={<>Kg</>} startAdornment={<Eye />} placeholder="Enter text..." size="xs" />
      </div>
    );
  };

export default function InputWithAdornmentsExample(props: Partial<ComponentProps<typeof Input>>) {
  const mergedProps = { ...STORY_DEFAULT_ARGS, ...props } as ComponentProps<typeof Input>;
  return InputWithAdornmentsExampleRender(mergedProps);
}

Ghost

import type { ComponentProps } from 'react';
import { Input } from '@mildang/design-system/Input';

const STORY_DEFAULT_ARGS = { ...({}), ...({ ghost: true }) } as ComponentProps<typeof Input>;

const InputGhostExampleRender = (args: ComponentProps<typeof Input>) => <Input placeholder="Search" size="lg" {...args} />;

export default function InputGhostExample(props: Partial<ComponentProps<typeof Input>>) {
  const mergedProps = { ...STORY_DEFAULT_ARGS, ...props } as ComponentProps<typeof Input>;
  return InputGhostExampleRender(mergedProps);
}

MaxLength

import { useState } from 'react';
import { Input } from '@mildang/design-system/Input';
import { Text } from '@mildang/design-system/Text';

const InputMaxLengthExample = function Render() {
    const MAX = 4;
    const [year, setYear] = useState('');

    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12, width: 320 }}>
        <Input
          placeholder="ex) 1999"
          maxLength={MAX}
          inputMode="numeric"
          value={year}
          onChange={(e) => setYear(e.target.value)}
          endAdornment={
            <>
              {year.length}/{MAX}
            </>
          }
          fullWidth
        />
        <Text variant="body-md" color="neutral.text.low">
          {MAX}자를 넘겨 입력해도 브라우저가 막습니다.
        </Text>
      </div>
    );
  };

export default InputMaxLengthExample;

NativeAttributes

import { Input } from '@mildang/design-system/Input';

const InputNativeAttributesExample = () => (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16, width: 320 }}>
      <Input placeholder="ex) 1999" maxLength={4} inputMode="numeric" fullWidth />
      <Input placeholder="010-0000-0000" type="tel" autoComplete="tel" fullWidth />
      <Input placeholder="읽기 전용" defaultValue="수정 불가" readOnly fullWidth />
    </div>
  );

export default InputNativeAttributesExample;

CustomStyle

import { Input } from '@mildang/design-system/Input';

const InputCustomStyleExample = () => (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      <Input width="30px" placeholder="" size="sm" />
      <Input width="120px" placeholder="120px" size="md" />
      <Input width="300px" placeholder="300px" size="lg" />
      <Input width="500px" placeholder="500px" size="lg" />
      <Input placeholder="fullWidth" size="lg" fullWidth />
    </div>
  );

export default InputCustomStyleExample;

StateMatrix

import type { ComponentProps } from 'react';
import { Input } from '@mildang/design-system/Input';
import { Text } from '@mildang/design-system/Text';

/** Figma 상태 매트릭스: 행=상태(Inactive/Hover/Active/Focus/Focus&Text/Disable), 열=타입(Default/Error/Warning/Success) */
const MATRIX_TYPES = [
  { key: 'default', label: 'Default', props: {} },
  { key: 'error', label: 'Error', props: { error: true } },
  { key: 'warning', label: 'Warning', props: { warning: true } },
  { key: 'success', label: 'Success', props: { success: true } },
] as const;

const MATRIX_ROWS = [
  { key: 'inactive', label: 'Inactive', value: '', pseudo: null },
  { key: 'hover', label: 'Hover', value: '', pseudo: 'hover' },
  { key: 'active', label: 'Active', value: 'text', pseudo: null },
  { key: 'focus', label: 'Focus', value: '', pseudo: 'focus' },
  { key: 'focus-text', label: 'Focus & Text', value: 'text', pseudo: 'focus' },
  { key: 'disable', label: 'Disable', value: 'text', pseudo: null, disabled: true },
] as const;

const cellId = (rowKey: string, typeKey: string) => `matrix-${rowKey}-${typeKey}`;

const STORY_DEFAULT_ARGS = { ...({}), ...({ size: 'xl' }) } as ComponentProps<typeof Input>;

const InputStateMatrixExampleRender = (args: ComponentProps<typeof Input>) => (
    <div
      style={{
        display: 'grid',
        gridTemplateColumns: `120px repeat(${MATRIX_TYPES.length}, 240px)`,
        gap: '16px 24px',
        alignItems: 'center',
        padding: '8px',
      }}
    >
      <div />
      {MATRIX_TYPES.map((type) => (
        <Text key={type.key} variant="title-sm-medium" color="neutral.text.low">
          {type.label}
        </Text>
      ))}

      {MATRIX_ROWS.flatMap((row) => [
        <Text key={`${row.key}-label`} variant="title-sm-medium">
          {row.label}
        </Text>,
        ...MATRIX_TYPES.map((type) => (
          <Input
            key={`${row.key}-${type.key}`}
            size={args.size}
            placeholder="placeholder"
            defaultValue={row.value || undefined}
            disabled={'disabled' in row ? row.disabled : false}
            _containerId={cellId(row.key, type.key)}
            fullWidth
            {...type.props}
          />
        )),
      ])}
    </div>
  );

export default function InputStateMatrixExample(props: Partial<ComponentProps<typeof Input>>) {
  const mergedProps = { ...STORY_DEFAULT_ARGS, ...props } as ComponentProps<typeof Input>;
  return InputStateMatrixExampleRender(mergedProps);
}