ComponentsText & numbersDatetime
On this page
Text & numbers

Datetime released

A day and a time of it, typed into two texts under one label or picked in one panel holding a calendar and columns of hours and minutes.

  • Import@pacit/components/datetime
  • Selectorpct-datetime

Implements the W3C ARIA APG Date Picker Dialog pattern ↗

Type it, or pick the day and then the time

datetime.demo.ts — the same file runs here and is highlighted under Code

Start here

Usage

One import per component, and the shortest possible use — the package itself is installed once, on the start page.

Import this component
import { PctDatetime } from '@pacit/components/datetime';
ExportedWhat it is
PctDateTimetypeunreleasedstringA day and a time of it, written the way the platform already writes one: YYYY-MM-DDTHH:mm, or YYYY-MM-DDTHH:mm:ss where the field's step has seconds in it — a PctDay, a T and a PctTimeOfDay.
PctDateTimePartsinterfaceunreleasedThe two halves of a datetime — what the field's two texts hold.
isPctDateTimefunctionunreleasedWhether a string is a datetime this library will work with: a PctDay, one capital T, and a PctTimeOfDay — each half held to its own guard, so the domain is theirs: the day runs from 0000-01-01 to 275760-09-13 and the time refuses 24:00, a leap second and a fraction.
pctDateTimefunctionunreleasedJoins a day and a time into one value, in the time's shape: 13:05 makes …T13:05, and 13:05:00 makes …T13:05:00.
pctDateTimePartsfunctionunreleasedThe two halves of a datetime, each in the shape it was written in. The caller has already established that it is one.
pctDateTimeAsUtcfunctionunreleasedThe pair as the one Date anything outside this file is allowed to see: those fields in UTC — which is what Intl.DateTimeFormat with timeZone: 'UTC' reads back as the same day and time, exactly, in all three engines (0090, B9). It is the day's pctDayAsUtc with an hour on it, and it is not an instant anybody meant: no zone the event happens in is asked.
pctCompareDateTimesfunctionunreleased-1, 0 or 1 — the days first, then the times. …T13:05 and …T13:05:00, one value in two shapes, compare equal; and the day's compare reads a year of five digits as later than one of four, where a string compare would not.
pctClampDateTimefunctionunreleasedHeld inside the bounds, either of which may be absent — undefined, as the FormUiControl contract spells an absent bound. A clamp invents no value: it hands back the one it was given or a bound, as written, and a value equal to a bound in the other shape is inside.
pctAddDateTimeMinutesfunctionunreleasedn minutes on (or back), and the day carries: …01T23:30 plus 45 minutes is …02T00:15. That is PlainDateTime's answer and the platform's own — a datetime input's stepUp() at 23:59 is the next day's 00:00 in all three engines, where the same call on a time input stops or comes round (0090, A10 and B7). The time's shape is kept: a whole minute never moves the seconds.
pctNowDateTimefunctionunreleasedThe day and the time on the LOCAL clock — the one read of local time in this file, and the only one that belongs: "what day and what time is it" is a question about where the user is standing, and every other question here is arithmetic on a value that already has an answer.
PctDateTimePredicatetypeunreleased(value: PctDateTime) => booleanA predicate on a datetime: true refuses it — a slot already taken on a day.
PctDatetimePanelAligntypeunreleased'start' | 'end'Which edge of the field the panel lines its own up with.
PctDatetimecomponentunreleasedpct-datetimeDatetime field — two texts under one label, the day's and the time's, each formatted and parsed per locale, with ONE button and ONE panel holding a calendar and columns of hours and minutes. It is the ARIA APG's Date Picker Dialog whole, through PctCalendar as PctDate holds it, with the time's columns beside the grid — a role="listbox" per field, claimed on their own card.
PctDateTimeBoundtypeunreleasedPctDateTime | undefined | LogicFn<TValue, PctDateTime | undefined, TPathKind>A bound pctDateTimeBounds takes: a datetime, or a function of the field's context that returns one — the two shapes Angular's own min() takes. One that is not a datetime, undefined among them, is no bound, as it is on the field's input.
PctDateTimeBoundErrortypeunreleased| { readonly kind: 'minDateTime'What pctDateTimeBounds reports: minDateTime for a datetime before min, maxDateTime for one after max — and both at once for one between the two of a reversed pair, the native element's reading on a datetime (0090, A8). Each carries the bound it broke, as the bound was written.
PctDateTimeBoundsConfiginterfaceunreleasedThe bounds of pctDateTimeBounds, and the sentence its errors carry — one for both, or one written from the error, which holds the bound.
pctDateTimeBoundsfunctionunreleasedBounds a datetime field in a signal form: what Angular's min() / max() do for a number and minDate() / maxDate() for a Date, for a PctDateTime — which none of them takes (their paths are a number's and a Date's, and the latter read the value with getTime()), and which the compiler refuses as an attribute beside [formField] (NG8022). The bounds reach the field's min / max, so the calendar and the columns walk inside them, and the form grades the value: a datetime outside is minDateTime or maxDateTime.
<pct-datetime label="Starts" [(value)]="startsAt" />
Examples

Every state, running

Each example is the component itself, not a screenshot. Open the code under any of them.

In other languages

Which half stands first, the day's order and the clock all come from Intl for the field's locale — the time first in Vietnamese. One value, written three ways.

Within bounds, around taken slots

min and max are a day and a time: the calendar gets the day of each, the columns the time of a bound only on the bound's own day. dateDisabled refuses a day whole; datetimeDisabled is asked of every time of the chosen day, and an hour every slot of which is taken is refused.

API

What it reads, and what it writes back

Read from the source at build time — the types, the defaults and the lines of documentation are the library's own.

unreleased marks 41 of them: on main, and not in @pacit/components@0.2.0 — the next release names the version.

Datetime field — two texts under one label, the day's and the time's, each formatted and parsed per locale, with ONE button and ONE panel holding a calendar and columns of hours and minutes. It is the ARIA APG's Date Picker Dialog whole, through PctCalendar as PctDate holds it, with the time's columns beside the grid — a role="listbox" per field, claimed on their own card.

Inputs

NameTypeWhat it does
valuetwo-wayunreleaseddefault nullPctDateTime | nullThe chosen day and time, or null — which it is until both halves hold one.
disabledunreleaseddefault falsebooleanBlocks the control and greys it — the native disabled on both texts, so they leave the tab order as well. With [formField] the directive writes it, as it writes every input of the FormUiControl contract.
readonlyunreleaseddefault falsebooleanKeeps the value: both texts take the native readonly and the button is disabled with them, while the field stays focusable.
invalidunreleaseddefault falsebooleanThe form's verdict; shown only once touched, so an empty form does not open red.
touchedunreleaseddefault falsebooleanWhether the user has left the field once; with invalid it gates the error face.
requiredunreleaseddefault falsebooleanMarks the label with the required sign; with [formField] it follows the schema's required().
errorsunreleaseddefault []readonly ValidationError.WithOptionalFieldTree[]The form's validation errors; the first one's message takes the hint's place once the field is touched.
warningsunreleaseddefault undefinedreadonly ValidationError.WithOptionalFieldTree[] | undefinedA verdict without a veto (0087): shown after the error and before the hint once the field is touched, in the warning tone, with aria-invalid untouched. Left unbound, the control reads what pctWarn() wrote for its own [formField]; bound — [] included — the list given stands.
nameunreleaseddefault ''stringThe native name — what a form submission calls the value. It names a hidden input that carries the value as the platform writes one, YYYY-MM-DDTHH:mm, and not either text, which are written in the user's language.
minunreleaseddefault undefinedunknownThe earliest day and time. It belongs to the FormUiControl contract, which spells an absent bound undefined, and a signal form gives it through pctDateTimeBounds — the compiler refuses the attribute beside [formField].
maxunreleaseddefault undefinedunknownThe latest day and time — as min, a bound on the panel's walk and not a rewrite of what was typed.
stepunreleaseddefault 60numberThe step in seconds — the time's, 60 by default. It decides the columns' rows, whether a seconds column exists and whether the value carries :ss, and nothing about typed text. It counts from midnight on every day, not from min: a bound off the step is moved inward onto it before the columns see it (0090 §5). A step the columns cannot list is refused with a dev-mode warning and read as 60.
dateDisabledunreleaseddefault nullPctDayPredicate | nullDays inside the bounds that cannot be picked — handed to the calendar as it is, so a day it refuses is refused whole, hours included.
datetimeDisabledunreleaseddefault nullPctDateTimePredicate | nullSlots inside the bounds that cannot be taken — a meeting room's bookings. The field closes it over the chosen day and asks it of every time on the step, in the columns' rows: an hour is refused when every time in it is. It never reaches the calendar; a day whose every slot it refuses is still a day the grid offers, and a consumer who wants that day greyed says so through dateDisabled. A typed value it refuses is kept, and the form's to refuse.
labelunreleaseddefault ''stringThe visible label, rendered by the control itself when it stands outside a pct-field; inside one, the field's label is the name. Each text is named by it and a word of its own.
hintunreleaseddefault ''stringA line of help under the control, outside a pct-field; the first error message takes its place while the field is invalid and touched.
ariaLabelunreleaseddefault ''stringThe accessible name of a field with no visible label — an INPUT rather than an aria-label on the tag, because the texts sit inside this template and an ARIA name on the roleless host is ignored. Each text is named by it and a word of its own.
ariaLabelledbyunreleaseddefault ''stringAs ariaLabel, for a name that already stands somewhere on the page.
localeunreleaseddefault ''stringOverrides the application's LOCALE_ID for this field — the order of the two texts, the day's order and the clock all follow it.
firstDayOfWeekunreleaseddefault 0numberWhich day the calendar's week starts on, 1 (Monday) … 7 (Sunday). Absent, the locale decides.
showFormatunreleaseddefault truebooleanWhether the two format hints stand in the texts while they are empty (dd.mm.yyyy and hh:mm).
sizeunreleaseddefault config.defaultSizePctSizeHeight 28 / 36 / 44 px — the axis every field shares; from providePctConfig by default (req-api-config).
panelAlignunreleaseddefault 'start'PctDatetimePanelAlignWhich edge of the field the panel lines up with.

Outputs

NamePayloadWhen it fires
touchunreleasedvoidEmitted when focus leaves the whole field — both texts, the button and the panel — and not when it moves between them; lets the form mark the field as touched.

What it writes on the element

The hooks a stylesheet or a test can hold. Stable by contract — the parts inventory gate fails the build when one disappears.

AttributeBound toNote
classpct-datetime
data-pct-sizesize()
data-pct-openopen() ? "" : null
data-pct-invalidshowInvalid() ? "" : null
data-pct-warningshowWarning() ? "" : null
data-pct-disableddisabled() ? "" : null
data-pct-malformedmalformed() ? "" : nullWhat the control knows and the form cannot: there is text in a half and it is not one.
data-pct-in-fieldinField ? "" : null
Styling

Parts to select, tokens to override

Two ways in, both stable. No class names to depend on.

Parts

In a test, PctDatetimeHarness from @pacit/components/testing reads a part by the name below and a state by its attribute — the harness gate holds the names to the package.

PartSelectorWhat it is
date-control[data-pct-part="date-control"]the day's text
error[data-pct-part="error"]the message when the value is invalid, or a half is not one, or one is missing
hint[data-pct-part="hint"]the hint under the field
label[data-pct-part="label"]the label of the field, pointing at the text that stands first
panel[data-pct-part="panel"]the dialog the calendar and the columns stand in
time-control[data-pct-part="time-control"]the time's text
toggle[data-pct-part="toggle"]the button that opens the panel
warning[data-pct-part="warning"]the message when the value is allowed and suspect — after the error, before the hint (0087)

Tokens

Every value the component reads, with the light and the dark default. Override a token at any scope and it cascades like any custom property.

TokenStyles
--pct-datetime-bg{pct.surface}#ffffff · #0f172aBackground of the datetime field.
--pct-datetime-bg-disabled{pct.surface-disabled}#f1f5f9 · #1e293bBackground of the datetime field while disabled.
--pct-datetime-border{pct.border-strong}#64748bEdge colour of the datetime field.
--pct-datetime-border-disabled{pct.border}#e2e8f0 · #334155Edge colour of the datetime field while disabled.
--pct-datetime-border-focus{pct.primary}#2563eb · #60a5faEdge colour of the datetime field when focused.
--pct-datetime-border-hover{pct.text-muted}#334155 · #e2e8f0Edge colour of the datetime field on hover.
--pct-datetime-border-invalid{pct.danger}#b91c1c · #f87171Edge colour of the datetime field when invalid.
--pct-datetime-border-warning{pct.warning}#b45309 · #fbbf24Edge colour of the datetime field under a warning (0087).
--pct-datetime-fg{pct.text}#0f172a · #ffffffText colour of the datetime field.
--pct-datetime-fg-disabled{pct.text-disabled}#64748bText colour of the datetime field while disabled.
--pct-datetime-fg-invalid{pct.danger}#b91c1c · #f87171Text colour of the datetime field when invalid.
--pct-datetime-fg-warning{pct.warning}#b45309 · #fbbf24Text colour of the warning line (0087).
--pct-datetime-font-size{pct.font.size.md}14pxFont size of the datetime field.
--pct-datetime-font-size-lg{pct.font.size.lg}16pxFont size of the datetime field at size lg.
--pct-datetime-font-size-sm{pct.font.size.sm}13pxFont size of the datetime field at size sm.
--pct-datetime-hint-fg{pct.text-muted}#334155 · #e2e8f0Text colour of the hint.
--pct-datetime-icon-size16pxSize of the icon.
--pct-datetime-label-fg{pct.text}#0f172a · #ffffffText colour of the label.
--pct-datetime-padding-x{pct.space.4}12pxHorizontal padding of the datetime field.
--pct-datetime-padding-x-lg{pct.space.4}12pxHorizontal padding of the datetime field at size lg.
--pct-datetime-padding-x-sm{pct.space.3}8pxHorizontal padding of the datetime field at size sm.
--pct-datetime-padding-y{pct.space.3}8pxVertical padding of the datetime field.
--pct-datetime-padding-y-lg{pct.space.4}12pxVertical padding of the datetime field at size lg.
--pct-datetime-padding-y-sm{pct.space.2}4pxVertical padding of the datetime field at size sm.
--pct-datetime-panel-bg{pct.surface}#ffffff · #0f172aBackground of the panel.
--pct-datetime-panel-border{pct.border-strong}#64748bEdge colour of the panel.
--pct-datetime-panel-gap{pct.space.2}4pxGap between the calendar and the columns in the panel.
--pct-datetime-panel-padding-x{pct.space.3}8pxHorizontal padding of the panel.
--pct-datetime-panel-padding-y{pct.space.3}8pxVertical padding of the panel.
--pct-datetime-panel-radius{pct.radius.md}8pxCorner radius of the panel.
--pct-datetime-panel-shadow{pct.shadow-panel}0 8px 24px rgba(15, 23, 42, 0.14) · 0 8px 24px rgba(0, 0, 0, 0.55)Shadow of the panel.
--pct-datetime-placeholder-fg{pct.text-muted}#334155 · #e2e8f0Text colour of the placeholder.
--pct-datetime-radius{pct.radius.md}8pxCorner radius of the datetime field.
--pct-datetime-target-min{pct.target.min}24pxTouch-target floor of the datetime field.
--pct-datetime-toggle-bg-hover{pct.surface-100}#f1f5f9 · #1e293bBackground of the button that opens the panel on hover.
--pct-datetime-toggle-fg{pct.text-muted}#334155 · #e2e8f0Text colour of the button that opens the panel.
--pct-datetime-toggle-radius{pct.radius.md}8pxCorner radius of the button that opens the panel.
--pct-datetime-toggle-size20pxSize of the button that opens the panel.

Theming

A brand override in a few declarations. Scope it to a theme attribute, a page or one container — the component never notices.

[data-theme='brand'] {
  --pct-datetime-border-focus: #0f766e;
  --pct-date-day-bg-selected: #0f766e;
  --pct-time-option-bg-selected: #0f766e;
}
Type it, or pick the day and then the time
Accessibility

Measured, not assumed

Pattern: Date Picker Dialog — held whole, through PctCalendar as the date field holds it: a button beside the field opens a role="dialog" holding a role="grid", and beside the grid one named role="listbox" per field of the time, claimed on their own card (0090 §7). The two texts stand in a role="group" named by the label, and each is a plain textbox named by the label and a word of its own — deliberately not a combobox, for the date's reason (0035 read backwards)

Keyboard

keyeffecttest
any texttyped into a half, parsed when that half is leftapps/sandbox-e2e/src/datetime.spec.ts › junk in one half keeps the other
Tabthe first text → the second → the button → out; leaving the whole is touchapps/sandbox-e2e/src/datetime.spec.ts › a day with no time is no value
Enter on the buttonopens the panel, focus on the grid's cell — the held day, or todayapps/sandbox-e2e/src/datetime.spec.ts › opens on the day and the time the field holds
arrows in the gridwalk the days, as on PctCalendarapps/sandbox-e2e/src/datetime.spec.ts › a day picked moves on to the hours
Enter in the gridwrites the day's text, leaves the time's as typed, and hands focus to the hour columnapps/sandbox-e2e/src/datetime.spec.ts › a day picked moves on to the hours, libs/components/datetime/src/datetime-field.spec.ts
Tab in the panelthe month buttons, the grid's cell, then the columns one stop each — the grid firstapps/sandbox-e2e/src/datetime.spec.ts › Tab walks the grid, then the columns
Shift+Tab from the hoursback to the grid's cell — the way to a day picked wrongapps/sandbox-e2e/src/datetime.spec.ts › Tab walks the grid, then the columns
arrows in a columnwrite the time as they walk, as on PctTimeColumnsapps/sandbox-e2e/src/datetime.spec.ts › a day picked moves on to the hours
Enter in a columntakes the time and closes the panel, focus back on the first textapps/sandbox-e2e/src/datetime.spec.ts › a day picked moves on to the hours
Escape in the panelcloses it with the value as the halves left it, focus back on the first textapps/sandbox-e2e/src/datetime.spec.ts › Escape closes it, libs/components/datetime/src/datetime-field.spec.ts
Tab out of the panelcloses it, focus spliced back onto the first textapps/sandbox-e2e/src/datetime.spec.ts › Tab walks the grid, then the columns

The grid's and the columns' own maps are on their cards. The field adds no key of its own: what a user types is text, and the arrows do not step the segment under the caret, because the engines step the native element's segments three ways (0090, A10) and a reader is never told a textbox has a value to step.

What is measured, and what is not yet

Every line is a test in three engines or a gate on every commit. The gaps are listed the same way, each with the requirement that will close it.

MeasuredARIA APG pattern in the JSDoclibs/components/datetime/src/datetime-field.ts — the pattern, the reasons and the decision behind them in the class comment
MeasuredKeyboard mapapps/sandbox-e2e/src/datetime.spec.ts — the panel's map in three engines; libs/components/datetime/src/datetime-field.spec.ts — Escape, Tab off either end and inside, a pick in the grid and in a column, key by key
Measuredaxe auditapps/sandbox-e2e/src/a11y.spec.ts — the /datetime view and /all, and separately the open panel with the field it belongs to: the group, the two named textboxes, the toggle's aria-controls into the overlay, the grid and the named listboxes
MeasuredVisual screenshotapps/sandbox-e2e/src/visual.spec.ts — datetime-field, datetime-panel and datetime-panel-rtl
Measuredforced-colors: activeapps/sandbox-e2e/src/forced-colors.spec.ts — a half that is not one draws the row's edge twice as thick, a shape the substitution keeps, and the panel keeps an edge in CanvasText; the grid's and the columns' own readings are on their cards
Measuredprefers-reduced-motiontools/check-styles.mjs point 9 — the row's transition takes --pct-motion-transition-duration, which the token build switches off
MeasuredTouch target ≥ 24×24 pxapps/sandbox-e2e/src/target-min.spec.ts — the button is max(--pct-datetime-toggle-size, --pct-datetime-target-min), measured with the drawing disarmed
MeasuredSize axisapps/sandbox/src/app/views/size/size-view.html — the /size view puts the field on the shared sm/md/lg axis beside the date and the time fields, and the grid and the rows follow it into the panel
GapDensity axisnone — gap (req-token-density has not one token in the sources)
MeasuredRTLapps/sandbox-e2e/src/datetime.spec.ts › right to left — the two texts and the button change sides and the columns stand after the grid on the left; apps/sandbox-e2e/src/visual.spec.ts — datetime-panel-rtl
MeasuredSSR + hydrationapps/sandbox-e2e/src/hydration.spec.ts — the /datetime view is in SBX_ROUTES
MeasuredFormslibs/components/datetime/src/datetime-field.spec.ts › the forms that bind it — [formField], [formControl] and [(ngModel)], each from a non-empty value (lesson-26); apps/sandbox-e2e/src/forms.spec.ts — the field in a signal form that stays invalid with a day and no time on the screen; a form's reset — reset() keeping the value, reset(value) showing it, the form pristine: libs/components/datetime/src/datetime-field.spec.ts › the forms that bind it
MeasuredBounds from a signal formlibs/components/datetime/src/datetime-field.spec.ts › bounds from a signal form (pctDateTimeBounds) — the bounds reach the field and the calendar and the columns walk inside them, a datetime outside is minDateTime / maxDateTime and a bound is inside in either shape, a reversed pair is under and over, the message, a bound read off another field beside a fixed one in the same rule, two rules walked as their intersection in either order, years past 9999 and one instant in two shapes, rules that meet in no datetime handing no bounds and no warning, and Angular's minDate() refused by the compiler; apps/sandbox-e2e/src/datetime.spec.ts › bounds from a signal form — the bounds reaching the panel and a datetime typed outside reported, in three engines
MeasuredMessage announcedtools/check-aria.mjs (point 7, target check-aria) — the error part carries role="alert", the warning part role="status"
MeasuredValue as lawslibs/components/datetime/src/datetime.property.spec.ts — the arithmetic against the platform's millisecond count over the whole domain, both ends; libs/components/datetime/src/datetime.spec.ts › in a hostile timezone (req-api-datetime)
MeasuredParts in the inventorylibs/components/parts.snapshot.md, tools/check-parts.mjs (target check-parts)
MeasuredTokens + contrast.policy.jsonlibs/tokens/src/contrast.policy.json — 18 pairs for the field's own tier, the calendar's days and the columns' rows on its panel among them
MeasuredStrings through PCT_TEXTStools/check-texts.mjs — four keys of its own; the two halves' sentences and letters are the date's and the time's, so no key is added for them
MeasuredSize budgetlibs/components/size.snapshot.md, tools/check-bundle.mjs (target check-bundle) — the ./datetime row, the date's and the time's entrypoints included
MeasuredNot a value, saidlibs/components/datetime/src/datetime-field.spec.ts › junk in a half and › a half left empty — three sentences on the second channel, one at a time; apps/sandbox-e2e/src/datetime.spec.ts — the same in three engines, in French (0070)
MeasuredScreen-reader logRead 2026-10-12 from docs/acr/at/ — three readers, whole sandbox, and the act that opens the panel. Each text is the label and its word: Orca Starts · panel · Starts Jour · entry · 01/12/2026 · required. and then Starts Heure · entry · 09:30 · selected required.; NVDA Starts Heure, edit, required, Type it, or pick it in the panel, selected 09:30, and on the first text of each field the group alone, Starts, grouping; VoiceOver read one stop of the view on 2026-10-12, as on most views of that pass, and twelve on 2026-10-29. The button says what it opens: Choisir une date et une heure, button, collapsed, opens dialog (NVDA), Choisir une date et une heure · collapsed button. · opens dialog (Orca). Opening lands on the grid: Orca Choisir une date et une heure · dialog · décembre 2026. · table with 7 rows 7 columns · mardi column header 1 · row 2 column 2, NVDA Choisir une date et une heure, dialog and nothing of the grid; VoiceOver read the dialog and its grid on 2026-10-12, and on 2026-10-29 it opened the panel and said nothing. Escape from the grid closes the panel under all three, focus back on the day's text — Orca Starts Jour · entry · 01/12/2026. — where Escape from a column of /time, the same listbox, left NVDA's panel open in the same pass: under NVDA this panel closes on one Escape from its grid and needs two from a column (plan 4.82)
Measureddocs page/components/datetime on the published site — prerendered, the demo's own source is the code tab
Evidence

What the repository holds for this component

Read at build time from the tracked snapshots, not typed here.

85.64%mutation score692 of 808 mutants killed
15 × 3e2e cases × enginesplus the shared audits: axe, forced colors, preferences, size, hydration
18colour pairs measuredlight and dark, at every token build
3visual baselinesChromium, the sandbox's own pictures
13elements in the preview8 listeners · 1 render to settle · 6335 µs in jsdom, held exactly but for the clock

Decisions behind it

  • 0090A day with a time is a wall clock with a date, and the field that takes one is two texts under one label
  • 0093A bound of the field's own type reaches it through the platform's limit key, and the module ships the rule
  • 0086A time of day is a wall clock, and the field that takes one is text the application formats
  • 0089One value, more than one control, and the consumer chooses which
  • 0043A day is not an instant, and the field that takes one is text the application formats
  • 0070What the control knows and the form cannot is a second channel
  • 0035A filter is a question, not a value
  • 0031A panel's tab order belongs to its trigger
  • 0025A panel says whether it takes focus, and the rest of the focus layer waits for a consumer
  • 0024The overlay layer carries what an overlay severs, and borrows the closing stack
  • 0022One message line, and it is the error that takes it
  • 0005Signal forms without ControlValueAccessor
  • 0003Wrapper and control
  • lesson-26FormField supplies an NgControl itself

Known limitations

  • No zone, so neither the gap nor the overlap is refused. 02:30 on 29 March 2026 is a value of this field and does not exist on a wall in Warsaw; 02:30 on 25 October happens there twice. The control cannot know where the event is — in Lisbon both minutes are ordinary — so turning the pair into an instant, and choosing what the skipped and the repeated minute mean, is the application's: Temporal.PlainDateTime.from(value).toZonedDateTime(zone, { disambiguation }) where the engine has it.
  • A null from outside does not clear a half-filled field. A day typed with no time is null already, so a model or a form writing null over it changes nothing the field can see, and the day stays on the screen with its sentence; reset() — which a signal form's reset calls — takes the half back and writes both texts again from the value, empty here.
  • One day and time, not a range. A meeting's two ends are two fields with min / max bound to each other (0034) — in a signal form, pctDateTimeBounds with a bound read off the other field. A reversed pair is no window: the night shift is two datetimes on two days, and a time field's 22:00–06:00 ported here gets a warning and no bounds.
  • Rules that meet in no datetime leave the panel open. A start typed past the close hands the end's field no bounds: the panel offers every day and the form refuses every datetime, each rule with the bound it broke — no pair says "nothing" to a field that reads a reversed one as none. The field's warning is for its own attributes: a pair written reversed by hand in one rule warns of nothing either, and every datetime then carries the errors (0093).
  • No day without a time. A half-filled field says so, always, and there is no knob to let "required" win over it; a form that wants a day with an optional time is a date field and a time field.
  • Gregorian only. The calendar and both parsers read the Gregorian calendar, as the date field does; a -u-ca- extension changes nothing the field writes.
  • datetimeDisabled is asked per row, per day. 1 440 questions on the default step every time the chosen day changes — cheap for a Set, and the consumer's problem for a predicate that fetches.
  • The clock is the engine's. In chromium a Burmese, Nepali, Georgian, Armenian, Icelandic or Albanian field is written in the browser's default locale — the same engine's own Intl on the same page (0090, C4).
  • list columns only. The wheel shape the time panel will offer (0089, plan 1.7) reaches this field when it lands.