본문으로 건너뛰기
Amineslab UI

Component

Input

한 줄 텍스트와 숫자를 받는 HTML input 래퍼입니다.

Playground

옵션을 조절하며 화면과 사용 코드를 함께 확인하세요.

PC 1280px
Controls

비어 있을 때 힌트

control 높이

필드 표면

elevation 아래 불투명 테마 배경

오류 시각 상태와 aria-invalid

비활성

아이콘 컴포넌트, 문자열, ReactNode 또는 null을 전달합니다.

아이콘 컴포넌트, 문자열, ReactNode 또는 null을 전달합니다.

Code
import { Input } from '@amineslab/ui'

import { Mail, Check } from '@amineslab/ui/icons'

function slotText(value: string) {
    return value.startsWith('text:') ? value.slice(5) : value;
}

function slotKind(value: string): 'none' | 'icon' | 'node' | 'text' {
    if (value === 'icon' || value === 'node' || value === 'none')
        return value;
    return 'text';
}

function renderInputSlot(value: string, icon: typeof Mail) {
    switch (slotKind(value)) {
        case 'none':
            return null;
        case 'icon':
            return icon;
        case 'node':
            return <span className="font-semibold">단위</span>;
        case 'text':
            return slotText(value);
    }
}

export default function ExamplePreview() {
  return ((<Input aria-label="이메일" opaque={false} disabled={false} invalid={false} startAdornment={renderInputSlot("icon", Mail)} placeholder={"name@example.com"} size={"md"} variant={"filled"} endAdornment={renderInputSlot("none", Check)}/>))
}

Props

@amineslab/ui에서 Input를 가져옵니다.

import { Input } from '@amineslab/ui'

Input

HTML <input> 요소의 표준 속성을 그대로 받습니다.

NameTypeDefaultDescription
opaquebooleanfalse반투명 elevation 아래에 불투명한 테마 배경을 깝니다. Button의 opaque와 같습니다.
variant'filled' | 'outline''filled'입력 필드의 표면 표현입니다.
size'xs' | 'sm' | 'md' | 'lg' | 'xl''md'입력 요소의 높이와 내부 여백입니다.
invalidbooleanfalse오류 시각 상태와 aria-invalid를 활성화합니다.
startAdornmentReactNode | IconComponent-Mail 같은 아이콘 컴포넌트는 16px·보조색으로 표시합니다. 텍스트는 보조색·말줄임을 적용하고 슬롯 너비만큼 입력 여백을 확보합니다. ReactNode도 전달할 수 있습니다.
endAdornmentReactNode | IconComponent-Check 같은 아이콘 컴포넌트는 16px·보조색으로 표시합니다. 텍스트는 보조색·말줄임을 적용하고 슬롯 너비만큼 입력 여백을 확보합니다. ReactNode도 전달할 수 있습니다.
wrapperClassNamestring-입력 장식 래퍼에 추가할 클래스입니다.

Examples

자주 쓰는 조합을 살펴보고, 필요한 예시의 코드를 펼쳐 확인하세요.

Sizes

import { type ComponentPropsWithoutRef } from 'react'

import { cn } from '@amineslab/ui/utils'

import { type ControlSize, Input } from '@amineslab/ui'

const controlSizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const satisfies readonly ControlSize[];

const sizes = controlSizes;

function ExampleStack({ className, compact = false, fullWidth = false, ...props }: ComponentPropsWithoutRef<'div'> & {
    compact?: boolean;
    fullWidth?: boolean;
}) {
    return (<div {...props} className={cn('grid', compact ? 'w-auto gap-2' : fullWidth ? 'w-full gap-4' : 'w-full max-w-[360px] gap-3', className)}/>);
}

export default function ExamplePreview() {
  return ((<ExampleStack>
          {sizes.map((size) => (<Input aria-label={`검색 ${size}`} key={size} placeholder={`Size ${size}`} size={size}/>))}
        </ExampleStack>))
}

Left and right slots

startAdornment과 endAdornment은 아이콘 컴포넌트, 문자열, ReactNode를 받습니다. 아이콘은 컴포넌트 참조만 전달하고, 단위나 접두어는 문자열로 바로 넣을 수 있습니다.

₩
원
할인
%
import { type ComponentPropsWithoutRef } from 'react'

import { cn } from '@amineslab/ui/utils'

import { Input } from '@amineslab/ui'

import { Search, Mail, Check } from '@amineslab/ui/icons'

function ExampleStack({ className, compact = false, fullWidth = false, ...props }: ComponentPropsWithoutRef<'div'> & {
    compact?: boolean;
    fullWidth?: boolean;
}) {
    return (<div {...props} className={cn('grid', compact ? 'w-auto gap-2' : fullWidth ? 'w-full gap-4' : 'w-full max-w-[360px] gap-3', className)}/>);
}

export default function ExamplePreview() {
  return ((<ExampleStack>
          <Input aria-label="검색" startAdornment={Search} placeholder="검색"/>
          <Input aria-label="이메일" startAdornment={Mail} endAdornment={Check} defaultValue="hello@example.com"/>
          <Input aria-label="금액" startAdornment="₩" endAdornment="원" defaultValue="12,000"/>
          <Input aria-label="할인율" startAdornment={<span className="font-semibold">할인</span>} endAdornment={<span className="text-brand">%</span>} defaultValue="10"/>
        </ExampleStack>))
}

States

import { type ComponentPropsWithoutRef } from 'react'

import { cn } from '@amineslab/ui/utils'

import { Input } from '@amineslab/ui'

function ExampleStack({ className, compact = false, fullWidth = false, ...props }: ComponentPropsWithoutRef<'div'> & {
    compact?: boolean;
    fullWidth?: boolean;
}) {
    return (<div {...props} className={cn('grid', compact ? 'w-auto gap-2' : fullWidth ? 'w-full gap-4' : 'w-full max-w-[360px] gap-3', className)}/>);
}

export default function ExamplePreview() {
  return ((<ExampleStack>
          <Input aria-label="이메일 오류" defaultValue="hello@amineslab" invalid/>
          <Input aria-label="이메일 비활성" defaultValue="hello@amineslab.com" disabled/>
        </ExampleStack>))
}

TextField로 사용하기

TextField는 기본 입력에 label·required·description·error를 함께 제공합니다. FormStack 안에 직접 넣으며 FormField로 다시 감싸지 않습니다.

라벨·설명·필수 표시를 Field가 함께 처리합니다.

import { useState } from 'react'

import { TextField } from '@amineslab/ui'

const fieldDescription = '라벨·설명·필수 표시를 Field가 함께 처리합니다.';

function TextFieldExample() {
    const [value, setValue] = useState('');
    return (<TextField label="이름" description={fieldDescription} required value={value} onValueChange={setValue} placeholder="이름을 입력해 주세요"/>);
}

export default function ExamplePreview() {
  return (<TextFieldExample />)
}

사용 기준

권장하는 사용
  • 입력값에 맞는 HTML `type`과 `autocomplete`을 지정합니다.
피해야 할 사용
  • 숫자 키패드가 필요하다는 이유만으로 식별자에 number type을 쓰지 마세요.

접근성

화면에 맞는 이름을 제공하고, 키보드만으로 작업을 마칠 수 있는지 확인하세요.

  • Tab: input으로 포커스 이동