DateRangePicker

Data Input

시작일과 종료일 기간을 캘린더 그리드로 선택하는 입력 컴포넌트.

Usage

조회 기간처럼 시작일·종료일과 자주 쓰는 기간 preset을 함께 선택할 때 사용한다.

import

import

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

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

@mildang/styled-system 은 이 저장소에서 Panda 가 생성하는 산출물이다. 저장소 안에서는 turbo run ship 이후 쓸 수 있고, 패키지 소비자는 자기 Panda 산출물이나 다른 레이아웃 수단으로 바꿔야 한다.

외부 패키지를 따로 설치한다. DS 의 전이 의존성에 기대지 않는다.

API Reference

DateRangePicker Props

Prop

Type

Default

aria-label

string

지정 안 함

cancelText

string

지정 안 함

clearText

string

지정 안 함

confirmText

string

지정 안 함

disabled

boolean

지정 안 함

error

boolean

지정 안 함

excludeUnavailable

boolean

false

formatDisplay

(from: string, to: string) => string

지정 안 함

getDayClassName

(date: Date) => string

지정 안 함

inputProps

Omit<DateInputProps, "disabled" | "error" | "value" | "placeholder" | "readOnly">

지정 안 함

isDateUnavailable

(date: Date, firstSelectedDate?: Date) => boolean

지정 안 함

locale

string

지정 안 함

max

string

지정 안 함

min

string

지정 안 함

numOfMonths

number

2

onValueChange

(value: DateRangeValue) => void

지정 안 함

placeholder

string

지정 안 함

presets

DateRangePresetInput[]

지정 안 함

startOfWeek

0 | 1 | 4 | 2 | 3 | 5 | 6

지정 안 함

timeZone

string

Asia/Seoul

value

DateRangeValue

지정 안 함

같은 패밀리

@mildang/design-system/DateRangePicker 에서 같이 내보내는 컴포넌트다.

표시 형식

닫힌 입력에 보이는 문자열은 시작 · 종료 각각 useFormatDateTime 으로 만든 뒤 ' ~ ' 로 이어붙인다. 표시 형식 규칙 자체는 DatePicker 와 같다 — 자세한 내용은 DatePicker 문서의 "표시 형식" 참고. timeZone 도 동일하게 'Asia/Seoul' 하드코드다.

표시 형식 커스터마이즈

formatDisplay로 기간 표시 문자열을 커스터마이즈합니다.

import { useState } from 'react';
import { DateRangePicker, type DateRangeValue } from '@mildang/design-system/DateRangePicker';

export default function DateRangePickerCustomFormatExample() {
  const [value, setValue] = useState<DateRangeValue | undefined>({
    start: '2026-06-15',
    end: '2026-06-29',
  });
  const formatKorean = (iso: string) => {
    const [y, m, d] = iso.split('-');
    return `${y}년 ${Number(m)}월 ${Number(d)}일`;
  };
  return (
    <DateRangePicker
      value={value}
      onValueChange={(v) => setValue(v ?? undefined)}
      formatDisplay={(from, to) => `${formatKorean(from)} ~ ${formatKorean(to)}`}
      inputProps={{ width: '400px' }}
    />
  );
}

Preset menu

presets prop 하나만 넘기면 좌측 preset menu + "선택 초기화" 버튼이 자동 조립된다. preset menu 는 Popover(≥ 960px) 에서만 보인다 — 위 "화면 크기별 동작" 참고. 배열 원소는 아래 네 형태를 자유롭게 섞을 수 있다.

형태의미
'today' | 'yesterday'DS 가 timeZone 기준으로 오늘/어제를 직접 계산한다 (zag 내장 preset 이 아니다)
'last7Days' · 'thisMonth' · ...zag 내장 preset 13종. 로케일 · 오늘 기준 자동 계산
{ label, value }임의 라벨 + 문자열 preset 또는 { start, end } ISO range 를 직접 지정
{ label, onClick, selected? }preset 이 아닌 액션 항목("맞춤 설정" 등). caller 가 클릭 핸들러 · 선택 상태를 직접 제어

tsx

const presets = [
  'today',
  'yesterday',
  'last7Days',
  'last14Days',
  'last30Days',
  'last90Days',
  { label: '맞춤 설정', selected: customMode, onClick: () => setCustomMode(true) },
];

// presets={presets} value={value} onValueChange={(v) => setValue(v ?? undefined)}

Preset menu

기본 preset 메뉴를 표시합니다.

import { useState } from 'react';
import { DateRangePicker, type DateRangeValue } from '@mildang/design-system/DateRangePicker';

export default function DateRangePickerWithMenuExample() {
  const [value, setValue] = useState<DateRangeValue | undefined>(undefined);
  return (
    <DateRangePicker
      value={value}
      onValueChange={(v) => setValue(v ?? undefined)}
      presets={['today', 'yesterday', 'last7Days', 'last14Days', 'last30Days', 'last90Days', 'direct']}
    />
  );
}

사용자 지정 range preset

임의의 기간을 preset 항목으로 추가합니다.

코드

import { useState } from 'react';
import { Trans } from '@lingui/react/macro';
import { DateRangePicker, type DateRangeValue } from '@mildang/design-system/DateRangePicker';

export default function DateRangePickerWithDirectRangePresetExample() {
  const [value, setValue] = useState<DateRangeValue | undefined>(undefined);
  const upcomingWeekend = (() => {
    // 로컬 date 기준 다가오는 토요일 ~ 일요일 계산
    const iso = (d: Date) => {
      const y = d.getFullYear();
      const m = String(d.getMonth() + 1).padStart(2, '0');
      const day = String(d.getDate()).padStart(2, '0');
      return `${y}-${m}-${day}`;
    };
    const now = new Date();
    const daysUntilSaturday = (6 - now.getDay() + 7) % 7 || 7; // 오늘이 토요일이면 다음 주 토요일
    const saturday = new Date(now.getTime() + daysUntilSaturday * 86_400_000);
    const sunday = new Date(saturday.getTime() + 86_400_000);
    return { start: iso(saturday), end: iso(sunday) };
  })();

  return (
    <DateRangePicker
      value={value}
      onValueChange={(v) => setValue(v ?? undefined)}
      presets={[
        'today',
        'yesterday',
        'last7Days',
        { label: <Trans>이번 주말</Trans>, value: upcomingWeekend },
        'direct',
      ]}
    />
  );
}

Compound API

Convenience wrapper 대신 primitive 로 직접 조립할 수도 있다. Menu 는 반드시 Calendarmenu prop 으로 주입해야 zag ArkDatePicker.Root context 안에서 렌더된다.

Primitive역할
DateRangePicker.RootResponsivePopover 래퍼 (위 "화면 크기별 동작" 참고)
DateRangePicker.Trigger팝오버 트리거 slot. 보통 DateInput 을 넘긴다
DateRangePicker.Content카드 chrome + range variant 를 담는 컨테이너
DateRangePicker.Calendarrange 그리드 (numOfMonths 기본 2). menu prop 으로 좌측 preset menu 를 주입한다
DateRangePicker.Menupreset 목록 컨테이너. 우측 테두리(borderRight)가 있고, 폭은 고정값이 아니라 프리셋 아이템 폭(140px) + 테두리만큼 자연히 늘어난다
DateRangePicker.PresetTriggerpreset 아이템. 클릭 시 range 자동 세팅 + 현재 값과 비교해 selected 판정
DateRangePicker.MenuItemnon-preset 액션 아이템. selected 표시는 caller 가 직접 제어
DateRangePicker.ClearTrigger"선택 초기화" 버튼. range 가 비어 있으면 자동 disabled
DateRangePicker.Footer취소/확인 버튼을 두는 영역

Preset menu

기본 preset 메뉴를 표시합니다.

import { useState } from 'react';
import { DateRangePicker, type DateRangeValue } from '@mildang/design-system/DateRangePicker';

export default function DateRangePickerWithMenuExample() {
  const [value, setValue] = useState<DateRangeValue | undefined>(undefined);
  return (
    <DateRangePicker
      value={value}
      onValueChange={(v) => setValue(v ?? undefined)}
      presets={['today', 'yesterday', 'last7Days', 'last14Days', 'last30Days', 'last90Days', 'direct']}
    />
  );
}

예제

기본 사용

평상시 모습인 닫힌 기간 입력입니다. 캘린더만 필요하면 DateRangeCalendar 를 씁니다.

import { DateRangePicker, type DateRangeValue } from '@mildang/design-system/DateRangePicker';
import { useState } from 'react';

export default function DateRangePickerExample() {
  const [value, setValue] = useState<DateRangeValue | undefined>(undefined);
  return (
    <div style={{ display: 'inline-flex', flexDirection: 'column', gap: 12 }}>
      <DateRangePicker value={value} onValueChange={(v) => setValue(v ?? undefined)} />
      <div style={{ fontSize: 12, color: '#888' }}>
        선택된 값(ISO): {value ? `${value.start} ~ ${value.end}` : '없음'}
      </div>
    </div>
  );
}

입력과 비활성 상태

기본·오류·비활성을 나란히 둡니다. 값이 든 비활성은 조회 조건을 고정해 보여줄 때 씁니다.

import { DateRangePicker } from '@mildang/design-system/DateRangePicker';
import { VStack } from '@mildang/styled-system/jsx';

export default function DateRangePickerInputStatesExample() {
  return (
    <VStack alignItems="flex-start" gap="12">
      <DateRangePicker placeholder="조회 기간 선택" />
      <DateRangePicker placeholder="기간을 확인해 주세요" error />
      <DateRangePicker value={{ start: '2026-09-01', end: '2026-09-07' }} disabled />
    </VStack>
  );
}

초기값

초기 선택 범위가 있는 기간 입력입니다.

import { useState } from 'react';
import { DateRangePicker, type DateRangeValue } from '@mildang/design-system/DateRangePicker';

export default function DateRangePickerWithInitialValueExample() {
  const [value, setValue] = useState<DateRangeValue | undefined>({
    start: '2026-06-15',
    end: '2026-06-29',
  });
  return <DateRangePicker value={value} onValueChange={(v) => setValue(v ?? undefined)} />;
}

최소·최대 날짜

min/max 범위 안에서만 기간을 선택합니다.

import { useState } from 'react';
import { DateRangePicker, type DateRangeValue } from '@mildang/design-system/DateRangePicker';

export default function DateRangePickerMinMaxExample() {
  const [value, setValue] = useState<DateRangeValue | undefined>(undefined);
  return (
    <DateRangePicker
      value={value}
      onValueChange={(v) => setValue(v ?? undefined)}
      min="2026-06-01"
      max="2026-07-31"
      placeholder="6~7월만 선택"
    />
  );
}

비활성 전환

열린 기간 입력을 disabled 상태로 전환하는 동작을 확인합니다.

코드

import { useState } from 'react';
import { DateRangePicker, type DateRangeValue } from '@mildang/design-system/DateRangePicker';

export default function DateRangePickerDisabledTransitionExample() {
  const [value, setValue] = useState<DateRangeValue | undefined>(undefined);
  const [disabled, setDisabled] = useState(false);
  return (
    <div style={{ display: 'inline-flex', flexDirection: 'column', gap: 12 }}>
      <label style={{ fontSize: 12, cursor: 'pointer' }}>
        <input type="checkbox" checked={disabled} onChange={(e) => setDisabled(e.currentTarget.checked)} />{' '}
        disabled
      </label>
      <DateRangePicker value={value} onValueChange={(v) => setValue(v ?? undefined)} disabled={disabled} />
    </div>
  );
}

비활성

선택할 수 없는 기간 입력을 표시합니다.

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

const DateRangePickerDisabledExample = () => <DateRangePicker value={{ start: '2026-06-15', end: '2026-06-29' }} disabled />;

export default DateRangePickerDisabledExample;

오류

오류 상태의 기간 입력을 표시합니다.

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

const DateRangePickerErrorExample = () => <DateRangePicker error placeholder="에러 상태" />;

export default DateRangePickerErrorExample;

한 달 보기

numOfMonths=1로 한 달만 표시합니다.

import { useState } from 'react';
import { DateRangePicker, type DateRangeValue } from '@mildang/design-system/DateRangePicker';

export default function DateRangePickerOneMonthExample() {
  const [value, setValue] = useState<DateRangeValue | undefined>(undefined);
  return <DateRangePicker value={value} onValueChange={(v) => setValue(v ?? undefined)} numOfMonths={1} />;
}

세 달 보기

numOfMonths=3으로 세 달을 동시에 표시합니다.

import { useState } from 'react';
import { DateRangePicker, type DateRangeValue } from '@mildang/design-system/DateRangePicker';

export default function DateRangePickerThreeMonthsExample() {
  const [value, setValue] = useState<DateRangeValue | undefined>(undefined);
  return <DateRangePicker value={value} onValueChange={(v) => setValue(v ?? undefined)} numOfMonths={3} />;
}