Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelog
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone Select
Forms
Address InputCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowPost Listing WizardPricing PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAI Product PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePress PageProduct Tour PagePromo PageReferral PageResearch Report PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageSwitch PageTemplate Gallery PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Inputs

Timezone Select

Inputs

Timezone Select React component for Tailwind CSS v4

Time PickerAddress Input
Live props
Field
label
description
error
required
name
State
invalid
disabled
readOnly
defaultValue
defaultOpen
Appearance
groupBy
showOffset
showTime
format
highlightMatches
size
variant
radius
Content
suggestedLabel
detectLabel
placeholder
emptyText
clearLabel
toggleLabel
sheetTitle
cancelLabel
Behavior
detect
locale
clearable
openOnFocus
autoHighlight
fuzzy
virtualThreshold100
Layout
responsive
side
align
maxHeight360px
Code
import { TimeZoneSelect } from "@/components/ui/timezone-select"

<TimeZoneSelect />
  1. Home
  2. Components
  3. Inputs
  4. Timezone Select
Pro

Timezone Select React component for Tailwind CSS v4

v1.0.0·Added in 1.10.0

A searchable time zone picker with live UTC offsets, optional local times, region groups and a one-tap Use my time zone row.

Click or focus the field and the list opens with every time zone, grouped by region (or by offset), each row showing its UTC offset and, with showTime, the current time there, ticking each minute while the list is open. The first row, "Use my time zone", picks the browser's zone in one go, and suggested zones sit right under it. The field text is selected on focus, so typing replaces it with a search: a city ("tokyo"), a country for common zones ("india"), an abbreviation ("EST", "CET") or an offset ("+2", "utc-5", "+5:30") all find their zone, with the matching letters in bold. Offsets and names follow daylight saving time for the date you pass, or for today. Leaving a search without a pick (Escape, a click away) brings back the zone you had. Keyboard: ArrowDown and ArrowUp move, PageUp / PageDown jump, Enter picks, Escape closes. On a phone a tap opens a full-height search sheet with 48px rows and a Cancel button; a tap on a row fills the field and closes it.

Timezone Select is a Pro React component in the React input components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add timezone-select, together with Combobox, Text match, useControllableState and UIProvider and the npm package lucide-react.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add timezone-select

Pro item: the CLI needs a Pro account. See plans

Usage

Import TimeZoneSelect from @/components/ui/timezone-select.

import { useState } from "react"
import { Globe } from "lucide-react"
import { TimeZoneSelect } from "@/components/ui/timezone-select"

export function ProfileTimeZone() {
  const [timeZone, setTimeZone] = useState("America/New_York")
  return (
    <TimeZoneSelect
      label="Time zone"
      description="Used for reminders and weekly reports."
      leftIcon={<Globe />}
      value={timeZone}
      onValueChange={setTimeZone}
      suggested={["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles"]}
      suggestedLabel="United States"
      showTime
      name="timeZone"
    />
  )
}

Props

  • labeldefault ""
    ReactNode

    The label above the field; it also names the list and the phone sheet.

  • descriptiondefault ""
    ReactNode

    Helper text under the field, linked with aria-describedby.

  • errordefault ""
    ReactNode

    Replaces the description with an error and marks the field invalid.

  • requireddefault false
    boolean

    Adds the asterisk to the label and required to the input.

  • invaliddefault false
    boolean

    The invalid look without a message.

  • disableddefault false
    boolean

    Dims the field and blocks it.

  • readOnlydefault false
    boolean

    Shows the zone without letting anyone change it.

  • value
    string

    The chosen IANA id, like "America/New_York", when you control it. Older ids ("Asia/Calcutta", "Europe/Kiev") are read as their current names.

  • defaultValuedefault ""
    string

    The starting zone, uncontrolled. "" is empty.

  • onValueChange
    (value: string) => void

    Called with the IANA id of the picked zone (the browser's zone for the Use my time zone row).

  • timeZones
    string[]

    The zones to offer. Default: every zone the browser knows (Intl.supportedValuesOf), with UTC added, or a built-in list of about 55 common zones on older runtimes.

  • groupBydefault "region"
    "region" | "offset" | "none"

    region groups by the id's continent (Americas, Europe, Asia...) sorted by city; offset groups by UTC offset from west to east; none is one flat list from west to east.

  • showOffsetdefault true
    boolean

    The UTC offset at the end of each row, like "UTC−04:00". Grouping by offset puts it in the group titles instead.

  • showTimedefault false
    boolean

    The current local time in each row, refreshed every minute while the list is open.

  • formatdefault "long"
    "long" | "short"

    long puts the zone name under the city in each row ("Eastern Daylight Time"); short shows the city only. The name stays searchable either way, and the field always shows the city.

  • suggested
    string[]

    Zones listed first under suggestedLabel, like the ones your team uses. They move out of their region group.

  • suggestedLabeldefault "Suggested"
    string

    The title of the suggested group.

  • detectdefault true
    boolean

    Adds a first row that picks the browser's own time zone, when it is in the list.

  • detectLabeldefault "Use my time zone"
    string

    The text of the detect row; the detected zone shows under it.

  • date
    Date

    The instant used for offsets, names and times, so daylight saving time is right for a meeting next month. Default: now.

  • localedefault ""
    string

    Locale for zone names and times through Intl. Falls back to the UIProvider locale, then to the browser's. City names stay as in the IANA id.

  • regionLabels
    Partial<Record<string, string>>

    Group titles keyed by the id's first part: America, Europe, Africa, Asia, Australia, Pacific, Atlantic, Indian, Antarctica, Arctic and Other (UTC). Defaults in TIME_ZONE_REGION_LABELS.

  • placeholderdefault "Select a time zone"
    string

    Shown while the field is empty, also in the phone sheet's search box.

  • emptyTextdefault "No time zones found"
    string

    Shown when the search matches nothing.

  • clearabledefault false
    boolean

    An x while a zone is chosen; Escape on a closed list clears too.

  • clearLabeldefault "Clear"
    string

    The accessible name of the x button.

  • toggleLabeldefault "Show time zones"
    string

    The accessible name of the chevron button.

  • openOnFocusdefault true
    boolean

    Opens the full list as soon as the field gets focus, and again on a click, like a select. Off: the list opens when you type, press ArrowDown or use the chevron.

  • autoHighlightdefault true
    boolean

    The first match is highlighted while you search, so Enter picks it.

  • highlightMatchesdefault true
    boolean

    The matched letters of each zone in bold.

  • fuzzydefault false
    boolean

    Also matches letters in order with gaps ("lsa" finds Los Angeles), ranked last.

  • leftIcon
    ReactNode

    An icon before the text, like a Globe. Unsized svgs follow the size.

  • sizedefault "md"
    "sm" | "md" | "lg"

    32 / 40 / 48px like every field; md grows to 44px on touch screens.

  • variantdefault "soft"
    "soft" | "outline" | "underline" | "ghost"

    The box: a filled well, an outline, a bottom line, or nothing until hover.

  • radiusdefault "md"
    "none" | "sm" | "md" | "lg" | "full"

    Corner shape, scaled per size like the button (md is 8 / 10 / 12px).

  • defaultOpendefault false
    boolean

    Starts with the list (or the sheet) open. Pass open and onOpenChange to control it.

  • open
    boolean

    Whether the list is open, controlled.

  • onOpenChange
    (open: boolean) => void

    Called when the list opens or closes.

  • responsivedefault true
    boolean

    Below 768px the field opens a full-height search sheet instead of the popover.

  • sheetTitledefault "Time zone"
    string

    The phone sheet's title for screen readers (its visible header is the search box); a string label wins.

  • cancelLabeldefault "Cancel"
    string

    The text button next to the sheet's search box.

  • sidedefault "bottom"
    "top" | "right" | "bottom" | "left"

    Where the list opens; it flips when there is no room.

  • aligndefault "start"
    "start" | "center" | "end"

    How the list lines up with the field.

  • maxHeightdefault 360
    number

    The list's height limit in px, capped by the room on screen.

  • virtualThresholddefault 100
    number

    Above this many rows only the visible ones render (the full list has about 420).

  • renderOption
    (option, state: { selected, highlighted, disabled, ranges }) => ReactNode

    Replaces a row's content; the row element, its aria and its classes stay.

  • namedefault ""
    string

    Submits the IANA id through a hidden input.

  • id
    string

    The input's id; generated when left out.

  • onChange
    (event: ChangeEvent<HTMLInputElement>) => void

    The native event of every keystroke in the search, untouched.

  • container
    HTMLElement | null

    Portal target for the list and the sheet (default document.body).

  • fieldProps
    Partial<FieldProps>

    Anything else for the field wrapper: optional, labelAction, orientation, labelWidth, hideLabel.

  • classNames
    Partial<Record<"field" | "label" | "description" | "error" | "counter" | "root" | "box" | "input" | "leftIcon" | "spinner" | "clear" | "toggle" | "content" | "list" | "item" | "group" | "status" | "sheet" | "sheetSearch" | "cancel", string>>

    Extra classes for the inner parts, the same slots as the Combobox. content is the popover, sheet the phone sheet.

  • className
    string

    Extra classes for the outermost element: the Field when there is a label or message, else the combobox root.

  • ref
    Ref<HTMLInputElement> (a useRef object or an (el) => void callback)

    The search input. Other input props (onBlur, onKeyDown, autoFocus, aria-*, data-*) land on it too.

Parts

  • getTimeZoneOptions

    function

    Builds the option list the component uses: every zone with its city, region, offset, localized name, local time and search keywords, sorted west to east. It reads Intl, so call it in an effect or an event handler, not in a server render. Reuse it for your own list or a settings page.

    • timeZones
      readonly string[]

      The ids to describe. Default: every zone the runtime knows plus UTC.

    • datedefault "new Date()"
      Date

      The instant for offsets, names and times.

    • locale
      string

      Locale for names and times.

    • formatdefault "long"
      "long" | "short"

      How label is built.

    • returns
      TimeZoneOption[]

      One option per zone.

  • formatUtcOffset

    function

    The offset of a zone at an instant as text: formatUtcOffset("America/New_York", date) gives "UTC−04:00" in summer and "UTC−05:00" in winter, and "" for an unknown id.

    • timeZone*
      string

      An IANA id.

    • datedefault "new Date()"
      Date

      The instant.

    • prefixdefault "UTC"
      string

      Text before the sign, e.g. "GMT".

  • getUtcOffset

    function

    The offset of a zone at an instant in minutes east of UTC (-240 for New York in summer, 330 for Kolkata), NaN for an unknown id.

    • timeZone*
      string

      An IANA id.

    • datedefault "new Date()"
      Date

      The instant.

  • TIME_ZONE_REGION_LABELS

    constant

    The default group titles keyed by the id's first part (America: Americas, Indian: Indian Ocean, Other for UTC).

  • TimeZoneOption

    type

    { value, city, region, offset, offsetLabel, name, label, time, keywords }: one zone as getTimeZoneOptions returns it.

  • GetTimeZoneOptionsParams

    type

    The parameters of getTimeZoneOptions.

  • TimeZoneGroupBy

    type

    "region" | "offset" | "none".

  • TimeZoneFormat

    type

    "long" | "short".

  • TimeZoneSelectProps

    type

    The props of TimeZoneSelect: its own plus the Combobox field props it passes through.

Examples

With local time

showTime adds the current time to each row and ticks each minute while the list is open.

Grouped by offset

groupBy="offset" lists zones west to east under their UTC offset.

Suggested zones for a US team

suggested pins the zones your team uses to the top under a title you choose.

Offsets for a future date

date picks the instant for offsets and times, so a January meeting shows winter time.

In a settings form

required, a validation error, clearable and a hidden input for native forms.

Dependencies

lucide-reactcomboboxtext-matchuse-controllable-stateui-config

Files

  • components/ui/timezone-select.tsx

FAQ

Is the React Timezone Select component free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install Timezone Select?

Run npx wingo-ui@latest add timezone-select. It also adds the Wingo UI items it builds on (Combobox, Text match, useControllableState and UIProvider) and the npm package lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/timezone-select.

How does Timezone Select behave on phones?

Below 768px the field opens a full-height search sheet instead of the popover. The responsive prop controls this and is on by default.

See also

ComboboxSelectDate Time PickerCron PickerPhone InputSettings Page

More React input components

Duration PickerOTP InputAvatar UploadColor PickerCalendarSlider
All 37 React input components
PreviousTime PickerNext Address Input

Preferences

Emma Carter · emma@northwind.com

Reminders and reports follow this zone.

timeZone="America/New_York" · virtual > 100

Try “tokyo”, “india”, “CET” or “+5:30” · on phones: “Time zone” sheet with “Cancel”