Skip to content

Components · Date, time and scheduling

TimezoneSelect

Searchable IANA time zone picker labelled by UTC offset and city, with detected and pinned zones.

@rookcom/monarch-react/schedulingComponent

Detected and pinned zones

Reports and reminders use this zone.

Usage examples

Curated list, small

Purpose

Chooses an IANA time zone from every zone the runtime knows (about 420), labelled "(UTC+05:30) Kolkata" and sorted by offset, with search by city, country, offset or abbreviation. Replaces native selects and hard-coded lists of 15 zones. Import from @rookcom/monarch-react/scheduling.

Use when

  • A person, workspace, schedule or booking page needs a time zone.
  • A short curated list is enough: pass zones.

Avoid when

  • Showing a time in a zone: format it with Intl instead.
  • Picking a UTC offset rather than a place: offsets change with daylight saving time.

Design principles

  • Zones are places, not offsets: the value is the IANA id, and the label shows the offset for now (DST-aware).
  • The likely answer is first: the device’s zone under "Detected", then the product’s "Pinned" and "Recent" zones.
  • Same render on server and client: detection runs after mount, and now can be passed.
  • Legacy ids that browsers still report (Asia/Calcutta) select their current name (Asia/Kolkata).

API reference

import { TimezoneSelect, canonicalTimezone, formatUtcOffset, getTimezoneInfo, listTimezones } from '@rookcom/monarch-react/scheduling';
ExportKindRenderingRoot class
TimezoneSelectcomponentclient.mn-timezone-select
canonicalTimezoneutilityclient–
formatUtcOffsetutilityclient–
getTimezoneInfoutilityclient–
listTimezonesutilityclient–

Built on Combobox and accepts its input props (size, placeholder, invalid, disabled, limit, …). Forwards its ref to the input.

Helpers: getTimezoneInfo(zone, { now, locale }), listTimezones(), formatUtcOffset(minutes), canonicalTimezone(zone).

Generated from the TypeScript declarations of packages/react/src/components/scheduling/timezone-select.

Properties

Without Intl.supportedValuesOf (older browsers and Node) the list falls back to about 80 common zones; a value outside the list is still shown.

TimezoneSelect

Searchable IANA time zone picker, labelled by UTC offset and city and sorted by offset, with "Detected", "Pinned" and "Recent" sections. Search matches city, zone id, offset (`+5:30`, `utc-8`), long name and common country names. Offsets are DST-aware for `now`. Built on Combobox.

PropTypeDescription
childrenReactNode
classNamestring
clearablebooleanAllow clearing the selection with the clear button / Backspace on empty input.
clearOptionComboboxClearOptionThe list starts with an option that clears the selection, such as "Unassigned" or "No country".
closeOnSelectbooleanClose the list after a pick. Default: true, or false with `multiple` or `inline`.
defaultOpenboolean
defaultValuestring | null
detectedZonestring | nullThe zone shown under "Detected". Default: the device's zone, read after mount so server and client render the same. `null` hides the section.
disabledboolean
emptyMessageReactNodeShown when no option matches.
formatLabel((zone: TimezoneInfo) => string)Option label. Default `(UTC+05:30) Kolkata`.
idstring
inputValuestringText typed in the input (controlled). Use for server-side filtering.
invalidboolean
limitnumberRender at most this many matching options, with a message to keep typing. Default: all.
listLabelstringAccessible name of the listbox. Default: the Field label, `aria-label`, or "Options".
loadingbooleanShown while options load.
localestringLocale for long zone names ("India Standard Time"). Default `en-US`.
messages(Partial<TimezoneSelectMessages> & Partial<ComboboxMessages>)Interface text, for translation.
minSearchLengthnumberShortest query `onSearch` runs for; shorter queries show `emptyMessage`. Default 0.
nownumber | DateThe instant offsets are computed for. Default: the time of first render. Pass it to render the same on server and client.
onInputValueChange((text: string) => void)
onOpenChange((open: boolean) => void)
onValueChange((zone: string | null) => void)
openbooleanWhether the list is open (controlled). Ignored with `inline`.
pinnedstring[]Zones listed first under "Pinned", such as the workspace's offices.
recentstring[]Zones listed under "Recent", such as the person's last choices.
renderOption((option: ComboboxOption, state: ComboboxOptionState) => ReactNode)Custom option content. Default: media, label, description, hint and a check mark.
searchDebouncenumberMilliseconds to wait after typing before `onSearch`. Default 250.
size"sm" | "md" | "lg"
valuestring | nullSelected IANA zone id (controlled). Legacy ids select their current name (`Asia/Calcutta` → `Asia/Kolkata`); a zone the list does not contain is still shown.
zonesstring[]Limit the list to these zones. Default: every zone the runtime knows, or a static list.

Variants

PropValuesDescription
size'sm''md''lg'Height, as Combobox.

States

StateExposed asBehaviour
Sectionsrole="group""Detected", "Pinned", "Recent" and "All time zones" while nothing is typed.
Searching–A flat list of matches in offset order.
Emptyrole="status""No time zones match".
Selected / invalid / disabled–As Combobox.

Interaction behaviour

  • Typing filters by every word: city, IANA id, long name ("India Standard Time"), offset (+5:30, utc-8, +0530) or country and abbreviation for common zones ("india", "us pacific", "bst").
  • The full list is built only when the field is first focused or opened, so pages with many fields stay fast.
  • A zone listed under "Detected" or "Pinned" also appears in its place in "All time zones".

Keyboard support

KeysAction
ArrowDown / ArrowUpOpens the list, then moves.
PageDown / PageUp, Home / EndMoves ten zones, or to the first or last.
EnterSelects the active zone.
EscapeCloses and restores the selected label.

Accessibility

Role
combobox, controlling a listbox
Accessible name
A FieldLabel or aria-label.
  • Each option reads its offset, city, IANA id and long name.
  • Sections are labelled groups.
  • Inherits Combobox’s APG keyboard and aria-activedescendant support.

Responsive behaviour

  • The list matches the field width (at least 12rem); long descriptions wrap.

Theme support

  • Combobox tokens; the input uses tabular numbers so offsets line up.

Do and don't

Do

  • Store the IANA id the picker returns, not the offset.
  • Pin the zones the workspace already uses (offices, teammates).
  • Pass now when the page is server rendered and must match exactly.

Don't

  • Do not hard-code a short list of zones unless the product truly only supports those.
  • Do not show offsets without a place; "UTC+01:00" is London in summer and Lagos all year.
  • Combobox: The searchable select it is built on.
  • Select: For a handful of fixed choices.

Dependencies

KindDepends on
npm packagesreact
Monarch componentsCombobox

Uses only Intl; no time zone data is bundled beyond the fallback id list and search aliases.

Testing coverage

  • Offsets formatted; DST-aware offsets, city and long name for an instant; unknown zones fall back.
  • Static list when Intl.supportedValuesOf is missing; legacy ids canonicalised.
  • Detected, Pinned, Recent and All sections in offset order; device detection after mount.
  • Search by country, offset and "us pacific"; selects; empty message.
  • A value outside the list, a legacy value and a custom label.
CheckCovered
Axe in jsdomYes
Server renderingYes
Browser suitesVisual baselines: /__gallery/timezone-select; Cross-browser axe: /components/timezone-select

Tests: packages/react/src/components/scheduling/timezone-select