@get-asset/sdk

Date Picker

One control for both jobs: a calendar period or a custom range, behind a mode switch. It owns the switch and the popover only — the two panels are a DatePicker.Period.Root and a DatePicker.Range.Root mounted inside it, both editing AssetProvider's single dateFrom/dateTo range. That range is what every date-driven component reports on, so a choice here moves the whole page.

Preview

Loading preview…

Anatomy

Import the primitive and compose the parts you need.

<DatePicker.Root>
<DatePicker.Anchor>
<DatePicker.Trigger><DatePicker.Value /></DatePicker.Trigger>
</DatePicker.Anchor>
<DatePicker.Portal>
<DatePicker.Content>
<DatePicker.ModeSwitch>
<DatePicker.ModeOption mode="period" />
<DatePicker.ModeOption mode="range" />
</DatePicker.ModeSwitch>
<DatePicker.PeriodMode>
<DatePicker.Period.Root>{/* period panel */}</DatePicker.Period.Root>
</DatePicker.PeriodMode>
<DatePicker.RangeMode>
<DatePicker.Range.Root>
<DatePicker.Range.Calendar />
</DatePicker.Range.Root>
</DatePicker.RangeMode>
</DatePicker.Content>
</DatePicker.Portal>
</DatePicker.Root>

API reference

Root props

PropTypeDefaultDescription
mode"period" | "range"Locks the picker to a single panel and hides the mode switch. Omitted, both panels are offered. Mount "period" on a surface built around period-over-period comparisons, so the range always names a month, quarter or year.
disabledbooleanDisables the trigger and the mode switch.

Parts

Popover

PartDescription
DatePicker.Value
asChild?, format?
Formats the provider range: "All 2026", "Q3 2026", "Mar 2026", or "1 Jan – 31 Mar 26" when it matches no calendar period.
DatePicker.Anchor
asChild?
Anchors the popover to the trigger.
DatePicker.Trigger
asChild?
Opens the popover on the mode matching the current range.
DatePicker.PortalRenders content outside clipping ancestors.
DatePicker.Content
asChild?
Modal popover content, carrying the active mode as `data-mode`.

Mode switch

PartDescription
DatePicker.ModeSwitch
asChild?
Accessible group wrapping the two mode options. Renders nothing while Root's mode prop locks the panel.
DatePicker.ModeOption
mode, asChild?
Switches to "period" or "range", defaulting to the labels Period and Custom. Reflects the active mode as aria-pressed and data-active.
DatePicker.PeriodModeRenders its children only while the period panel is active.
DatePicker.RangeModeRenders its children only while the custom-range panel is active.

Panels

PartDescription
DatePicker.Period.*The period panel compound: Root, Group, YearOption, QuarterOption, MonthOption, PreviousYear, DisplayYear, and NextYear. Root takes min, max, and disabled.
DatePicker.Range.*The custom-range panel compound: Root and Calendar. Root takes min, max, and disabled; the calendar picks a range in a three-click cycle.

Hook

PartDescription
DatePicker.useDatePicker()Returns the active mode, the provider range, its exact period when it has one, open state, and the mode and open actions.

Modes

Both panels are views of the same canonical range, so switching modes never writes to the provider. Move from Period to Custom and the calendar opens on the days the chosen period covers; move back and the period grid still shows that period selected.

Every date-driven component under the provider follows the committed range, unless it was detached with its own dateFrom/dateTo props. Cards that compare against a previous period can only do so period-over-period when the range names one, so a surface built around those comparisons should mount the picker with mode="period"; a custom range is compared against the same number of days immediately before it.

Opening lands on the mode that matches what is selected: an exact calendar year, quarter, or month opens on Period, anything else on Custom. A range picked in Custom that happens to be a whole month is an exact period, so the next open shows Period with that month selected. A fixed mode always opens on its own panel instead.

Composition

The nested roots keep their own props: pass min and max to the DatePicker.Period.Root and DatePicker.Range.Root you mount inside PeriodMode and RangeMode. DatePicker.Root takes only mode and disabled, since the bounds belong to the panel that enforces them.