Sakuga Back to Sakuga
Theme
Sound
Jump to a component

Core · Forms

DateField

DateField picks a date, or a range of dates read by period: this month, the quarter, the dates on an invoice. A record people read by period, a campaign's start and end.

@anicanon/sakuga/uiv1.0Used onWeb

Live, from @anicanon/sakuga 2.0.0

Sakuga for iOS and Android is coming

iOS

Web only

DateField is made for the web, and isn’t part of Sakuga for iOS yet.

Android

Web only

DateField is made for the web, and isn’t part of Sakuga for Android yet.

Use it for
A date or a span of dates someone picks or reads by period.
Not for

Guidelines

  • range makes it a range: the calendar shows two months beside the presets ({label, start, end}, a list a screen reader hears named by presetsLabel, default "Presets"). Without it, one month and one date.
  • value is {start, end} for a range and a string for a date, both 'YYYY-MM-DD'. onChange gets the same.
  • The field writes the dates the viewer's way (Intl, locale, default the viewer's): "Oct 1 – 23, 2026". When the value is a preset, the preset's name comes first, muted.
  • A preset applies in one press and closes. A range of your own takes two presses, the start and then the end, and the band follows the pointer between them. A press before the start begins again from there. A date takes one press. Escape closes without a change.
  • min and max keep days out of reach; they show muted and can't be picked.
  • align: 'end' lines the open calendar up with the field's end edge, for a field at the end of a toolbar.
  • The range is one pale band; its start and end are solid ink, as Button's primary is, and invert with it in dark. The accent is only today's dot. In a range, each month's grid leaves the other month's days blank; a single date shows them muted.
  • Where two months don't fit beside the presets (a phone), the range shows one month with the presets above it.
  • Opened by open or a pointer, the focused day draws no ring until a key is pressed; opened from the keyboard, it does.
  • For a board: open, month (the first month shown, 'YYYY-MM' or a day in it), today and weekStartsOn (default from the locale) fix what it shows.
  • A range can also be set in one gesture: press on the start, slide to the end and let go; sliding backwards sets the range the other way round. Let go where no day in reach was crossed, and only the start is set, as after a first press.
DateFieldExample.jsxReact
import { DateField } from '@anicanon/sakuga/ui';

const presets = [
  { label: 'This month', start: '2026-10-01', end: '2026-10-23' },
  { label: 'Last month', start: '2026-09-01', end: '2026-09-30' },
  { label: 'Last 30 days', start: '2026-09-24', end: '2026-10-23' },
  { label: 'Last 90 days', start: '2026-07-26', end: '2026-10-23' },
  { label: 'This year', start: '2026-01-01', end: '2026-10-23' },
];

export default function DateFieldExample() {
  return (
    <DateField
      label="Dates"
      range
      open
      today="2026-10-23"
      max="2026-10-23"
      month="2026-09-01"
      locale="en-US"
      value={{ start: '2026-10-01', end: '2026-10-23' }}
      presets={presets}
    />
  );
}

PropsDateFieldProps

label
string
hint
string
disabled
boolean
placeholder
string
range
boolean
value
string | DateRange
onChange
(value: string | DateRange) => void
presets
{ label: string; start: string; end: string; }[]
presetsLabel
stringDefault 'Presets'
min
string
max
string
open
boolean
month
string
The first month shown, 'YYYY-MM' or any day in it ('YYYY-MM-DD'); anything else falls back to the default.
today
string
'YYYY-MM-DD'. Default the real today.
locale
string
Default the viewer's.
weekStartsOn
number
0 is Sunday. Default from the locale.
align
'start' | 'end'Default 'start'
The open calendar lines up with the field's start or end edge.
previousLabel
string
Default "Previous month" and "Next month".
nextLabel
string
optional
boolean
As on TextField.
help
{ title?: string; text: ReactNode; }
maxWidth
number
id
string
className
string

Types

type DateRange = {
    start: string;
    end: string;
};
DateFieldExample.swiftiOS · coming soon
DateFieldExample.ktAndroid · coming soon

Each token reads a role, and the role lands on a value in each theme. Change the role and every component that reads it follows.

Space and shape

datefield-icon-size
select-value-icon-size
20px
datefield-chevron-size
select-chevron-icon-size
16px
datefield-disabled-opacity
opacity-disabled
0.35
datefield-body-gap
gap-xl
16px
datefield-months-gap
gap-xl
16px
datefield-month-gap
gap-xs
4px
datefield-nav-size
icon-button-size
44px
datefield-day-size
size-control-sm
36px
datefield-weekday-height
size-control-sm
36px
datefield-day-focus-offset
its own value
calc(-1 * 2px)
datefield-today-size
state-dot-size
6px
datefield-today-bottom
inset-xs
4px
datefield-today-radius
radius-full
9999px
datefield-forced-band-width
line-hairline
1px

Type

datefield-title-font
text-label
600 14px/20px "Funnel Sans", system-ui, -apple-system, "Segoe UI", sans-serif
datefield-weekday-font
text-small
500 12px/16px "Funnel Sans", system-ui, -apple-system, "Segoe UI", sans-serif
datefield-day-font
text-body
400 14px/20px "Funnel Sans", system-ui, -apple-system, "Segoe UI", sans-serif
datefield-end-font-weight
weight-strong
600

Motion

datefield-duration
motion-fast
160ms
datefield-easing
ease-standard
cubic-bezier(0.2, 0, 0, 1)

Checked automatically with axe-core 4.11.4 against WCAG 2.2 A and AA, on the live preview above, in light and dark, on 26 October 2026.

Result
No issues found, in light or in dark.
By design
The field is a button named by label and the dates, that opens a dialog named by label. Each month is a grid named by its month and year, with one Tab stop: arrows move a day or a week, Page Up and Page Down a month (with Shift a year), Home and End to the start and end of the week, and Enter or Space picks. Days in the range are selected, days out of reach disabled, and today is the current date; the new month is announced when it changes. The presets are a listbox with one Tab stop. Escape, a press outside or Tab out of it closes, and after Escape focus goes back to the field. Sliding across days is for the pointer; two presses, or the keys, do the same.
Not tested
The automated check doesn't test keyboard use, focus order or what a screen reader says. The lines above are the design system's own account of them.