Date and Time Picker
Allows users to select a date, time, or combined date-time value from a structured input. Use in forms wherever a precise date or time value is required. Don't use for simple date-only input where time is irrelevant.
FigmaDescription
Provides a structured input for capturing date, time, or combined date-time values. It presents a calendar picker and/or time selector that reduces manual text entry errors and enforces a consistent date format across forms.
Consultation scheduling forms, stakeholder meeting bookings, event creation workflows, deadline and due date fields, and any form field requiring a specific point in time or calendar date.
Free-text date fields produce inconsistent formats and validation failures that frustrate users and corrupt data. A structured picker enforces a valid value at point of entry, reducing downstream data quality issues in government records and consultation management.
Anatomy
| Part | Required? | Notes |
|---|---|---|
| Field label | Required | Visible label associated via for/id. Must describe the expected value — for example, 'Consultation close date' or 'Meeting start time'. Do not rely on placeholder text as a label. |
| Date input segment | Required | Structured text input or segmented day/month/year fields. Accepts keyboard entry and is connected to the calendar popover. |
| Time input segment | Optional | Hour and minute fields, with optional AM/PM toggle for 12-hour format. Only present in date-time or time-only variants. |
| Calendar trigger button | Recommended | Icon button (calendar icon) that opens the calendar popover. Must be keyboard-accessible and labelled with aria-label. |
| Calendar popover | Recommended | Floating panel containing a month grid. Includes previous/next month navigation and today highlight. Dismissed on selection or Escape. |
| Month/year navigation | Required | Controls inside the calendar popover for stepping through months and years. Must be operable by keyboard. |
| Helper text | Optional | Supplementary guidance below the input, such as expected format ('DD/MM/YYYY') or constraints ('Must be a future date'). |
| Error message | Recommended | Replaces or follows helper text when validation fails. Must be linked to the input via aria-describedby. |
| Clear button | Optional | Allows the user to remove a selected value. Only shown when a value is present and the field is not required. |
Variants
Date only
Captures a calendar date without a time component
Use for deadline dates, publication dates, event dates, or any context where time of day is not relevant — for example, a consultation close date.
Time only
Captures a clock time without a calendar date
Use when the date is already established by context and only the time needs to be set — for example, a recurring meeting time.
Date and time
Captures a precise moment combining both date and time
Use for scheduling specific events such as a stakeholder briefing, a consultation session start time, or a notification send time.
Date range
Captures a start date and an end date as a pair
Use for consultation windows, reporting periods, or filtering by date span. Both fields share a single calendar popover with range highlighting.
States
| State | Behaviour |
|---|---|
| Default | Input is empty and ready for interaction. Label and optional helper text are visible. |
| Focused | 3px focus ring using --op-color-interactive-focus appears on the active input segment or trigger button. Calendar popover opens when the trigger button receives focus and Enter/Space is pressed, or on click. |
| Filled | A selected value is displayed in the input. The clear button appears if the field is clearable. |
| Open (calendar popover visible) | The calendar popover is displayed. The trigger button is in a pressed state (aria-expanded='true'). Focus moves into the popover grid. |
| Disabled | Input and trigger button are non-interactive. Text renders at reduced opacity using --op-color-text-disabled. Not submitted with the form. |
| Read-only | Value is displayed but cannot be changed. Input has readonly attribute. Trigger button is hidden or non-interactive. Value is submitted with the form. |
| Error | Border changes to --op-color-status-error. Error message appears below the input, linked via aria-describedby. The error persists until a valid value is entered. |
| Loading | Used when available dates are fetched asynchronously (for example, checking consultant availability). A spinner replaces or overlays the calendar while data loads. |
Usage guidelines
When to use
- Setting a consultation close date or submission deadline in Open Point.
- Scheduling a stakeholder meeting or briefing session with a specific start date and time.
- Defining a date range for a community engagement period in Social Point.
- Setting a notification or reminder dispatch time in an automated workflow.
- Capturing a due date for a task or action item in a stakeholder record.
When not to use
- When only a year or a month/year is needed — use separate select inputs instead to avoid presenting an unnecessarily complex calendar.
- When the date is relative and imprecise (for example, 'in about two weeks') — use a plain text input or a duration selector.
- When the user is filtering or searching across a large date range — consider a dedicated date range filter component built for that context.
- When the date is not required and would rarely be provided — make it optional and clearly label it as such, or omit it entirely.
Do / Don't
Do
Label the field with specific, plain-language text that describes the value being captured, such as 'Consultation open date' or 'Meeting start time'.
Don't
Use generic labels like 'Date' or 'Pick a date' that leave users uncertain about what value is expected.
Do
Show the expected format in helper text when using a text-entry date input, for example 'DD/MM/YYYY'.
Don't
Rely on placeholder text alone to communicate the expected format — placeholder text disappears on focus and is not reliably read by screen readers.
Do
Set sensible min and max date constraints to prevent invalid input — for example, preventing a consultation close date from being set in the past.
Don't
Allow users to select dates outside a valid range and then surface a validation error after submission.
Do
For date-time fields, confirm the user's timezone where it is relevant to the action, particularly for scheduled notifications or cross-jurisdiction consultations.
Don't
Silently assume server timezone without surfacing it to the user, which can cause missed meetings or incorrectly timed notifications.
Do
Preserve a partially entered value when the user navigates away and returns, where the form supports draft saving.
Don't
Clear the field silently if the user opens and closes the popover without selecting a date — this is disorienting.
Layout & Spacing
Field label: margin-bottom --op-space-4 (4px) Input container: min-height 44px; padding-inline --op-space-12 (12px); padding-block --op-space-8 (8px) Helper text / error message: margin-top --op-space-4 (4px) Calendar popover: margin-top --op-space-4 (4px) from the input; padding --op-space-16 (16px) Calendar day cell: min-width 36px; min-height 36px; gap --op-space-4 (4px) between cells Month navigation buttons: min 44x44px touch target Time input segments: min-width 48px; gap --op-space-8 (8px) between hour and minute
Tokens
| Part | Token | Value |
|---|---|---|
| Input border (default) | --op-color-border-default | 1px solid. Increases to 2px on focus. |
| Input border (error) | --op-color-status-error | 1px solid; replaces default border when field is in error state. |
| Input background | --op-color-bg-primary | White/surface background. Does not change on focus. |
| Input text | --op-color-text-primary | Primary text colour for entered values. |
| Placeholder / helper text | --op-color-text-secondary | Used for format hints and supplementary guidance. |
| Error message text | --op-color-status-error | Matches border colour to reinforce the error state visually. |
| Focus ring | --op-color-interactive-focus | 3px solid outline, 2px offset. Applied to input segments and trigger button. |
| Calendar trigger button icon | --op-color-interactive-default | Icon colour for the calendar trigger. Uses --op-color-interactive-hover on hover. |
| Calendar popover background | --op-color-bg-primary | Surface colour for the floating calendar panel. |
| Calendar popover border | --op-color-border-default | 1px solid border on the popover container. |
| Selected date cell background | --op-color-interactive-default | Filled background on the selected day. Text uses --op-color-text-on-interactive. |
| Today highlight | --op-color-interactive-default | Underline or dot indicator only (not filled) to differentiate from selected state. |
| Disabled input | --op-color-text-disabled | Reduced-opacity text. Background uses --op-color-bg-disabled. |
| Date range in-range highlight | --op-color-interactive-default | At 15% opacity for cells between start and end dates. |
Engineering notes
- The date-time picker does not have a native wa-* Web Awesome counterpart. Implement using the browser-native , , or element as the baseline, progressively enhanced with a custom calendar popover for cross-browser consistency and Orbit styling.
- Always associate the label element with the input using matching for/id attributes. If using a fieldset for a date range pair, use a legend for the group label.
- Wire aria-describedby on the input to the IDs of both the helper text element and the error message element (space-separated). Toggle the error message element visibility and content in response to validation state.
- Set aria-expanded='true'/'false' on the calendar trigger button to reflect popover open state. Set aria-haspopup='dialog' on the trigger button.
- The calendar popover must have role='dialog' with an aria-label such as 'Choose date'. Wrap day cells in a role='grid' with role='gridcell' for individual cells.
- When the popover opens, move focus to the currently selected date cell, or to today's date if no value is set. When the popover closes (via Escape or date selection), return focus to the trigger button.
- For date ranges, manage focus order so that the start date input is reached before the end date input. Validate that the end date is not before the start date and surface the error on the end date field.
- Respect prefers-reduced-motion — suppress any slide/fade animation on the calendar popover open/close if the user has requested reduced motion.
- For government forms that will be archived or audited, store and display dates in ISO 8601 format (YYYY-MM-DD) internally, while formatting for display according to the locale (DD/MM/YYYY for Australia).
- When min or max date constraints are applied, mark out-of-range day cells with aria-disabled='true' and prevent selection. Do not remove them from the DOM as this confuses calendar navigation.
Keyboard interaction
| Key | Action |
|---|---|
| Tab | Moves focus to the date input segment, then to the time input segment (if present), then to the calendar trigger button, then to the clear button (if visible). |
| Enter / Space | Opens the calendar popover when focus is on the trigger button. Selects the focused day cell when the popover is open. |
| Escape | Closes the calendar popover and returns focus to the trigger button. |
| Arrow Left / Right | Moves focus between day cells within the calendar grid. Wraps to the previous or next month row as needed. |
| Arrow Up / Down | Moves focus between weeks in the calendar grid (7 days per step). |
| Page Up / Page Down | Navigates to the previous or next month in the calendar popover. |
| Home / End | Moves focus to the first or last day of the current week in the calendar grid. |
| Backspace / Delete | Clears the current segment value when focus is in the input. Activates the clear button when focus is on it. |
Why it matters
Government forms are frequently used by people with disabilities, including those who use screen readers or keyboard-only navigation. Date and time inputs are particularly error-prone for these users when implemented poorly — missing labels, focus traps in calendar popovers, and inaccessible grid navigation are common failure points. Accessible date pickers reduce barriers to participation in public consultations and government services.
Focus
Focus ring is 3px solid --op-color-interactive-focus with a 2px offset, applied to all interactive elements: input segments, the trigger button, clear button, and calendar day cells. When the calendar popover opens, focus transfers to the selected date cell or to today's date if no value is set. The popover must not create a focus trap — Escape must always return focus to the trigger button. When the popover closes (by selection or Escape), focus returns to the trigger button. In the date range variant, focus moves from the start date trigger to the end date trigger after the start date is selected, guiding the user through the two-step selection.
ARIA
| Role or attribute | When to use | Example |
|---|---|---|
aria-label (trigger button) | Provides an accessible name for the icon-only calendar trigger button. | <button aria-label="Open date picker" aria-haspopup="dialog" aria-expanded="false"> |
aria-expanded (trigger button) | Reflects whether the calendar popover is currently open. | <button aria-expanded="true" aria-haspopup="dialog"> |
role="dialog" + aria-label (popover) | Identifies the calendar popover as a dialog and gives it an accessible name. | <div role="dialog" aria-label="Choose date" aria-modal="true"> |
role="grid" (calendar table) | Marks the day grid as an interactive grid, enabling grid navigation keys. | <table role="grid" aria-labelledby="calendar-month-label"> |
aria-selected (day cell) | Marks the currently selected date in the calendar grid. | <td role="gridcell" aria-selected="true" tabindex="0"> |
aria-disabled (day cell) | Marks out-of-range or unavailable dates as non-interactive without removing them from the grid. | <td role="gridcell" aria-disabled="true" tabindex="-1"> |
aria-describedby (input) | Links the input to both helper text and error message elements for programmatic description. | <input type="text" aria-describedby="dob-hint dob-error"> |
aria-live="polite" (error message) | Announces validation errors to screen reader users without interrupting their current action. | <p id="dob-error" aria-live="polite" role="alert">Please enter a valid date.</p> |
Contrast
Label text (--op-color-text-primary on --op-color-bg-primary): must meet 4.5:1 minimum ratio. Helper text (--op-color-text-secondary on --op-color-bg-primary): must meet 4.5:1 minimum ratio — verify this token combination in the Orbit token audit, as secondary text tokens can fall below threshold. Error text (--op-color-status-error on --op-color-bg-primary): must meet 4.5:1 minimum ratio. Selected day cell text (--op-color-text-on-interactive on --op-color-interactive-default): must meet 4.5:1 minimum ratio. Disabled input text (--op-color-text-disabled): contrast requirement is relaxed to 3:1 per WCAG 2.1 SC 1.4.3 exception for disabled controls, but aim higher where feasible.
Touch targets
All interactive elements — input segments, the calendar trigger button, clear button, month navigation arrows, and individual day cells — must meet the 44x44px minimum touch target. Day cells in the calendar grid may be visually smaller than 44px but must have padding or invisible hit areas to reach the minimum. This is critical for use on mobile devices in the field (for example, council officers completing forms on tablets).
Things to avoid
- Do not use placeholder text as a substitute for a visible label. Placeholder text is not reliably exposed to assistive technologies and disappears on input.
- Do not open the calendar popover automatically on focus of the text input — this interrupts keyboard users who want to type a date directly.
- Do not prevent text entry in the date input and force popover-only selection — some users find a keyboard-typed date faster and less disruptive.
- Do not use colour alone to indicate the selected date or today's date — pair colour with a shape, underline, or other visual indicator.
- Do not dismiss the popover immediately on mouse-down on a date cell — wait for mouse-up/click to confirm selection, to avoid accidental selections during scroll.