본문으로 건너뛰기
Amineslab UI

Component

DatePicker

PC Popover와 모바일 Bottomsheet로 전환되는 날짜·시간 입력입니다.

Playground

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

PC 1280px
Controls

트리거 높이와 여백

비어 있을 때 안내 문구

PC 시간 입력 / 모바일 시·분 휠을 함께 표시

showTime을 켜면 시간 표시 형식에 적용됩니다.

최소 날짜 YYYY-MM-DD

최대 날짜 YYYY-MM-DD

Code
import { useState } from 'react'

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

function DateExample({ size = 'md', placeholder = '날짜 선택', opaque = false, variant = 'filled', showTime = false, hourCycle = '24', disabled = false, invalid = false, minDate = '', maxDate = '', }) {
    const [value, setValue] = useState('');
    return (<div className="grid w-full max-w-md gap-3">
      <DatePicker size={size as ControlSize} placeholder={placeholder} opaque={opaque} variant={variant === 'outline' ? 'outline' : 'filled'} value={value} onValueChange={setValue} showTime={showTime} hourCycle={hourCycle === '12' ? 12 : 24} disabled={disabled} invalid={invalid} minDate={minDate || undefined} maxDate={maxDate || undefined}/>
    </div>);
}

export default function ExamplePreview() {
  return (<DateExample {...({"size":"md","placeholder":"날짜 선택","opaque":false,"variant":"filled","showTime":false,"hourCycle":"24","disabled":false,"invalid":false,"minDate":"","maxDate":""} as const)}/>)
}

Props

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

import { DatePicker } from '@amineslab/ui'

DatePicker

NameTypeDefaultDescription
size'xs' | 'sm' | 'md' | 'lg' | 'xl''md'Button과 같은 트리거 높이·여백입니다. 모바일은 높이에 8px을 더합니다.
valuestring-YYYY-MM-DD. showTime=true이면 YYYY-MM-DDTHH:mm입니다. 시간대가 없는 로컬 날짜·시간입니다.
onValueChange(value: string) => void-PC는 선택 즉시 호출합니다. 모바일 날짜+시간은 완료에서 한 번 호출합니다.
showTimebooleanfalse달력 하단 중앙에 TimeInput 인라인 시·분 선택을 표시합니다.
minDate / maxDatestring-선택 가능한 최소·최대 날짜(YYYY-MM-DD). 연·월 이동 범위에도 반영합니다.
onClose() => void-편집 완료 후 호출합니다. 모바일 날짜+시간의 취소에서는 호출하지 않습니다. 확정 시 onValueChange 다음에 호출합니다.
hourCycle12 | 2424시간 표시 형식. 12시간제는 오전/오후와 01~12, 24시간제는 00~23을 표시합니다. value/onChange의 시간은 항상 24시간 HH:mm입니다.
placeholderstring-미선택 트리거 문구이자 모바일 시트의 제목입니다.
disabledbooleanfalse트리거를 비활성화합니다.
invalidbooleanfalse오류 테두리와 aria-invalid를 적용합니다.
variant'filled' | 'outline''filled'입력 표면을 선택합니다.
id / classNamestring-트리거 식별자와 스타일을 전달합니다. 인라인 기간 선택에서는 그룹에 적용합니다.
aria-describedby / aria-invalidstring / AriaAttributes["aria-invalid"]-폼 설명·오류 메시지와 실제 트리거를 연결합니다.
aria-requiredAriaAttributes["aria-required"]-필수 입력 상태를 실제 트리거에 전달합니다.
onBlurFocusEventHandler<HTMLButtonElement>-트리거가 포커스를 잃을 때 호출합니다. RHF touched 처리에 사용합니다.
opaquebooleanfalseelevation 레이어 아래 불투명한 테마 바탕을 추가합니다. hover·focus·invalid 표현은 유지합니다.

Examples

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

공통 필드 표면

variant는 filled·outline 표현을, opaque는 elevation 아래의 불투명 바탕을 정합니다. focus와 hover는 중립 elevation을 사용하고 invalid 테두리는 포커스 중에도 유지합니다. NumberInput·PhoneInput·PasswordInput은 Input의 아이콘·문자열·ReactNode 슬롯을 상속합니다. SelectField에서는 같은 표면 props를 직접 지정하거나 triggerProps로 세부 설정할 수 있습니다.

투명 바탕
불투명 바탕
Outline + 불투명 바탕
<DatePicker />

<DatePicker opaque />

<DatePicker variant="outline" opaque />

날짜와 시간 · 확정과 취소

PC는 날짜·시간 변경을 즉시 반영합니다. 모바일은 하단 완료를 눌러야 확정하며 X·바깥 영역·아래로 끌기는 편집을 취소합니다.

import { useState } from 'react'

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

function DateExample({ size = 'md', placeholder = '날짜 선택', opaque = false, variant = 'filled', showTime = false, hourCycle = '24', disabled = false, invalid = false, minDate = '', maxDate = '', }) {
    const [value, setValue] = useState('');
    return (<div className="grid w-full max-w-md gap-3">
      <DatePicker size={size as ControlSize} placeholder={placeholder} opaque={opaque} variant={variant === 'outline' ? 'outline' : 'filled'} value={value} onValueChange={setValue} showTime={showTime} hourCycle={hourCycle === '12' ? 12 : 24} disabled={disabled} invalid={invalid} minDate={minDate || undefined} maxDate={maxDate || undefined}/>
    </div>);
}

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

선택 범위 제한

날짜 클릭뿐 아니라 연·월 이동 범위도 제한합니다.

import { useState } from 'react'

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

function DateExample({ size = 'md', placeholder = '날짜 선택', opaque = false, variant = 'filled', showTime = false, hourCycle = '24', disabled = false, invalid = false, minDate = '', maxDate = '', }) {
    const [value, setValue] = useState('');
    return (<div className="grid w-full max-w-md gap-3">
      <DatePicker size={size as ControlSize} placeholder={placeholder} opaque={opaque} variant={variant === 'outline' ? 'outline' : 'filled'} value={value} onValueChange={setValue} showTime={showTime} hourCycle={hourCycle === '12' ? 12 : 24} disabled={disabled} invalid={invalid} minDate={minDate || undefined} maxDate={maxDate || undefined}/>
    </div>);
}

export default function ExamplePreview() {
  return (<DateExample minDate="2026-01-01" maxDate="2026-12-31"/>)
}

모달·시트 안에서 선택

모바일에서는 부모 시트를 유지하며 중첩 Drawer가 열립니다. 작은 Popover로 돌아가지 않습니다.

import { Dialog, DialogTrigger, Button, DialogContent, DialogBody, DatePicker, type ControlSize } from '@amineslab/ui'

import { useState } from 'react'

function DateExample({ size = 'md', placeholder = '날짜 선택', opaque = false, variant = 'filled', showTime = false, hourCycle = '24', disabled = false, invalid = false, minDate = '', maxDate = '', }) {
    const [value, setValue] = useState('');
    return (<div className="grid w-full max-w-md gap-3">
      <DatePicker size={size as ControlSize} placeholder={placeholder} opaque={opaque} variant={variant === 'outline' ? 'outline' : 'filled'} value={value} onValueChange={setValue} showTime={showTime} hourCycle={hourCycle === '12' ? 12 : 24} disabled={disabled} invalid={invalid} minDate={minDate || undefined} maxDate={maxDate || undefined}/>
    </div>);
}

function NestedDateExample() {
    return (<Dialog>
      <DialogTrigger asChild>
        <Button variant="outline">모달 안에서 날짜 선택</Button>
      </DialogTrigger>
      <DialogContent title="일정 편집">
        <DialogBody>
          <DateExample showTime/>
        </DialogBody>
      </DialogContent>
    </Dialog>);
}

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

DateField로 사용하기

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

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

import { useState } from 'react'

import { DateField } from '@amineslab/ui'

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

function DateFieldExample() {
    const [value, setValue] = useState('');
    return (<DateField label="시작일" description={fieldDescription} required value={value} onValueChange={setValue}/>);
}

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

사용 기준

권장하는 사용
  • 사용처는 value와 onChange만 관리합니다.
  • 날짜만 선택하면 즉시 반영하고 닫힙니다.
  • 모바일 showTime은 전체 높이 시트에서 편집 후 완료로 확정하며, 취소하면 원래 값을 유지합니다.
피해야 할 사용
  • 겉모양만으로 사용을 결정하지 마세요.
  • 의미와 키보드 동작, 모바일에서의 흐름을 함께 확인하세요.

접근성

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

  • Enter / Space: 트리거에서 선택 표면을 엽니다.
  • Escape: 닫습니다. 모바일 날짜+시간의 임시 편집은 취소합니다.