The CWA is in heavy development
The CWA is still in alpha and not ready for production - some code and implementations are likely to change. If you would like to try out the CWA, please enjoy what we have provided and feel free to provide feedback, or get involved on GitHub.
Cwa Layer

Date and Time Pickers

The UI kit's date and time picker, calendar and segmented date field, what values they take, and how to fix a picker that shows no time.

The UI kit has three date components. The admin uses <CwaUiDatePicker> for a component's scheduled publish time and a route's Goes live date, and you can use all three in your own admin tabs and pages. Like the rest of the kit, they're auto-imported with the CwaUi prefix. They're built on reka-ui and ported from Nuxt UI's Calendar and InputDate.

Added in @cwa/nuxt 2.0.0-alpha.2.
ComponentWhat it isValue
<CwaUiDatePicker>A date and time field with a calendar popoverA UTC ISO string
<CwaUiCalendar>The calendar on its own@internationalized/date values
<CwaUiInputDate>The segmented field on its own@internationalized/date values

Use <CwaUiDatePicker> when you're storing a date in the API. The other two are the parts it's built from, for when you need a date without a time, a range, or several dates.

CwaUiDatePicker

<script setup lang="ts">
const goLive = ref<string | null>(null)
const now = new Date().toISOString()
</script>

<template>
  <CwaUiDatePicker v-model="goLive" label="Goes live" :min="now" />
</template>

The field has day, month, year, hour and minute segments, on a 24-hour clock. Editors type into a segment or step it with the arrow keys, or open the calendar with the button at the end of the field. Picking a day in the calendar keeps the time already set, or uses 09:00 if the field was empty.

IMAGE: CwaUiDatePicker with its calendar popover open: the date and time segments and the calendar button inside the field, and the month grid below with the month and year controls
PropTypeDefaultDescription
v-modelstring | null—The chosen moment as a UTC ISO string, such as 2026-10-01T08:30:00.000Z. null shows an empty field. The picker never emits null, so clear the value yourself if you need to.
labelstring—Shown above the field and used as its accessible name.
minstring—A UTC ISO string. Nothing earlier can be chosen or emitted: the earliest time is min rounded up to the next minuteStep, and an earlier value is replaced by it.
minuteStepnumber5How far the arrow keys move the minutes.
localestringen-GBSets the order and format of the segments and the calendar's month names.
disabledboolean—Disables the field and the calendar button.

Time Zones

The editor picks a time on their own computer's clock, and the picker converts it to UTC. Hovering the calendar button names the zone and its UTC offset: "Times are in Europe/London, UTC+01:00". The offset is the one at the chosen date, not today's, so a time on the other side of a clock change shows the offset that will apply then.

CwaUiCalendar

A calendar on its own. It uses the DateValue types from @internationalized/date. The module depends on it, but pnpm only lets your code import packages your app lists, so add it with the same major version (pnpm add @internationalized/date@^3) and keep to one copy, see Troubleshooting:

<script setup lang="ts">
import { today, getLocalTimeZone } from '@internationalized/date'
import type { DateValue } from '@internationalized/date'

const day = shallowRef<DateValue>()
const earliest = today(getLocalTimeZone())
</script>

<template>
  <CwaUiCalendar v-model="day" :min-value="earliest" />
</template>

The heading switches between the day, month and year views, and the arrow buttons move by a month or a year.

PropTypeDefaultDescription
v-modelDateValue | DateValue[] | DateRange | null—A single date, an array with multiple, or { start, end } with range.
rangeboolean—Select a start and end date.
multipleboolean—Select several dates. Ignored with range.
type'day' | 'month' | 'year'dayWhat a selection picks: a day, a month or a year. The views above it are still available for navigation.
minValue / maxValueDateValue—The earliest and latest date that can be chosen.
isDateDisabled(date: DateValue) => boolean—Disables the dates it returns true for.
isDateUnavailable(date: DateValue) => boolean—Marks the dates it returns true for as unavailable.
weekStartsOn0–61 (Monday)The first day of the week, where 0 is Sunday.
numberOfMonthsnumber—How many months to show side by side.
fixedWeeksbooleantrueAlways shows six weeks, so the height doesn't change between months.
localestringen-GBMonth and weekday names.
monthControls / yearControlsbooleantrueShow the previous/next month and previous/next year buttons.
viewControlbooleantrueLet the heading switch to the month and year views.
disabled / readonlyboolean—
initialFocusboolean—Focus the calendar when it mounts.

CwaUiInputDate

The segmented field on its own, without the calendar:

<CwaUiInputDate v-model="day" granularity="day" />
PropTypeDefaultDescription
v-modelDateValue | DateRange | null—A single date, or { start, end } with range.
rangeboolean—Show a start and an end field.
granularity'day' | 'hour' | 'minute' | 'second'—The smallest segment shown.
hourCycle12 | 24—The clock used for the hour segment.
step{ year?, month?, day?, hour?, minute?, second? }—How far the arrow keys move each segment.
minValue / maxValueDateValue—The earliest and latest value.
isDateUnavailable(date: DateValue) => boolean—Marks dates as unavailable.
localestringen-GBSets the order and format of the segments.
hideTimeZonebooleantrueHides the time zone segment of a zoned value.
disabled / readonlyboolean—
id / namestring—Passed to the field.

Anything in the default slot is shown at the end of the field. <CwaUiDatePicker> puts its calendar button there.

Troubleshooting: the Picker Shows No Time

If <CwaUiDatePicker> shows a date with no hour and minute, check the browser console for this warning:

[CWA] Two copies of @internationalized/date are installed, so reka-ui cannot read the date picker value and its time is not shown.

Your lockfile has two copies of @internationalized/date, so reka-ui doesn't recognise the date-time value the picker gives it. It can happen when your app already had reka-ui installed, for example through Nuxt UI, on an older version. Run this to keep one copy:

pnpm dedupe