Timezone Combobox
Canonical timezone search with UTC offsets for settings, events, and schedules.
Searchable timezone picker used wherever Cal needs a wall-clock timezone. Options come from the Feature timezone catalog with UTC offsets.
import { TimezoneCombobox } from "@calcom/features/timezone/components/timezone-combobox";Ownership
Feature — not @coss/ui/shared. The control depends on @calcom/features/timezone catalog helpers (getTimezoneItems, toCanonicalTimezone) and @calcom/i18n labels. Documenting it here does not mean relocating it.
Example
Use the Feature component directly. The user settings form keeps form dirtiness and the optional travel-schedule action outside the control:
<Controller
name="timeZone"
control={formMethods.control}
render={({ field: { value } }) => (
<Fieldset className="flex w-full flex-col gap-2">
<Label render={<FieldsetLegend />}>{t("timezone")}</Label>
<FieldGrid className="gap-6">
<Field className="contents">
<TimezoneCombobox
value={value}
onValueChange={(timezone) =>
formMethods.setValue("timeZone", timezone, {
shouldDirty: true,
})
}
/>
</Field>
{!watchedTzSchedules.length && (
<Button
className="w-fit"
variant="outline"
onClick={() => setIsTZScheduleOpen(true)}>
<CalendarIcon aria-hidden="true" />
{t("schedule_timezone_change")}
</Button>
)}
</FieldGrid>
</Fieldset>
)}
/>This is the canonical composition from user general settings. Keep timezone catalog generation, canonicalization, offset sorting, search, and localized empty states inside TimezoneCombobox; do not duplicate them in consumers or documentation.
The create page replaces the select button with a ghost button and shows a short summary instead of the full timezone name. The caller builds that summary; the combobox still owns search and the catalog.
<TimezoneCombobox
value={value}
data-testid="create-event-timezone"
triggerRender={<Button type="button" variant="ghost" />}
triggerContent={
<>
<ClockIcon aria-hidden="true" />
<span className="tabular-nums">{zone.offset}</span>
<span className="text-muted-foreground">{zone.city}</span>
</>
}
onValueChange={onChange}
/>API
| Prop | Type | Notes |
|---|---|---|
value | string | null | IANA timezone id |
onValueChange | (timezone: string) => void | Fires with the selected canonical id |
id | string | Optional trigger id, passed to the default select button |
disabled | boolean | Disables the combobox and the default select button |
data-testid | string | Defaults to timezone-select |
triggerRender | ReactElement | Replaces the default full-width SelectButton. The create page passes a ghost Button |
triggerContent | ReactNode | Replaces ComboboxValue. When set, the trigger's accessible name is the timezone label |
Call sites
| File | Notes |
|---|---|
apps/web/modules/settings/my-account/general-view.tsx | User general settings timezone |
apps/web/modules/events/create-event/create-event-sentence.tsx | Create-page ghost trigger with offset and city |
apps/web/modules/events/components/tabs/basics-tab.tsx | Event basics wall-clock timezone |
packages/features/schedules/components/availability-settings.tsx | Schedule availability timezone |
apps/web/modules/ee/organizations/general.tsx | Organization general settings |
Example URLs
Not exhaustive — a few places you can open locally (e.g. http://localhost:3000) to see this in product.
| Path | Notes |
|---|---|
/settings/my-account/general | User timezone |
/events/new | Create-page trigger |
/availability/<scheduleId> | Schedule timezone |
/settings/organizations/general | Org timezone (org admin) |
Source
On This Page