shadcn.io is not affiliated with official shadcn/ui
Time Zone Picker Dialog Block for React
A preferences page with its time zone dialog shown open: a search over 14 zones in four regions, each row with its city, UTC offset and the time there at one typed moment, a button that reads this device's zone on a press, and the chosen zone printed back on the page.
Installation
Overview
Let people choose a time zone by reading it, with this time zone picker for React with Base UI. It opens from the Preferences page of Zonefold, a remote-team planner: the page's header holds an outline Change time zone Button, and the page itself, a column of label and value rows with the Time zone row in text, is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The Dialog has an Input that searches by city or offset and a Listbox of 14 zones grouped as Europe, Americas, Asia and Pacific. Each row shows the city, its IANA name, the UTC offset and the time there at one fixed moment, worked out with Intl.DateTimeFormat for that zone. A ghost button reads the zone your browser reports when you press it and picks or adds that row. Save time zone is the only Shine Button; it prints the zone and its offset on the page's Time zone row. For preview the dialog is drawn open in place when the page loads; the header's button opens the real dialog. For calendars, planners, schedulers and any app that shows times.
FAQ
Why is the dialog already open, and what do I keep?
So you can see it without a click. On load the dialog is a copy drawn in place over the page: a native dialog element that isn't modal, so nothing is trapped, hidden or focused, and the page around the preview keeps working. The Change time zone button opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same ZoneFields component and share the block's state. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.
Where do the offsets and the times come from?
From Intl.DateTimeFormat with each zone's timeZone, read once at one typed moment, Friday 9 October 2026 at 14:30 UTC, so the list never changes with your clock and a poster never ages. The offset is the difference between the zone's own date parts and that moment, so it already includes daylight saving for that day (London reads UTC+01:00 then and Berlin UTC+02:00). Both are in the file as MOMENT; in your app use the date the meeting or the page is about, and store the IANA name, not the offset.
What does the device button do, and when does it read the zone?
Only when you press it, never on load. It reads Intl.DateTimeFormat().resolvedOptions().timeZone, which is real: whatever zone your browser reports. If that zone is in the list it is picked and scrolled into view; if it isn't it is added in a This device group at the top with its own offset and time. If the browser gives no usable name it says so in the status line instead.
Is it accessible from the keyboard?
Yes. The real dialog is named by its title and described by its sentence, focus starts on the search field, and Escape, Cancel and the close button return focus to the Change time zone button. Arrow Down in the field moves into the list, where the arrow keys move through the rows and Enter picks; Enter in the field with something typed picks the top match. The count under the field says how many zones match, and the status line says which zone was chosen. The trigger is passed to DialogTrigger through render, and the dialog is controlled with open and onOpenChange.
What stays local, and how do I wire it for real?
Nothing is saved: Save time zone changes the Time zone row of the drawn page and says so in the polite status line, and closing without saving lets the choice go. The 14 zones are typed in the file. In your app load the person's zone from their profile, keep the full IANA list (or the browser's Intl.supportedValuesOf("timeZone")), save the IANA name on the server, and show every time with that zone.
How does it look on a phone?
The copy shown on load docks to the foot of the page as a bottom sheet with its buttons pinned and the content scrolling above them, search first. Each row keeps its city and name on the start side and its time and offset on the end side, so a long list reads as one narrow column. The real dialog keeps the Dialog's own phone layout, a sheet stuck to the bottom of the screen.
Related
- Pro
World Clock Dialog
Time and schedulingA team page with its clocks dialog shown open: one slider that moves your time while every city's local time, day and 24-hour strip follow, the best overlap worked out from the strips, cities to add and remove, and a button that copies one line per city.
- Pro
A team intranet's profile page with its language and region dialog shown open: a Language tab with a searchable list of eight languages, a Region tab with country, first day of the week and clock, and a live preview that reformats a sample date, time, number and amount with Intl.
- Pro
Schedule Meeting Dialog
Time and schedulingA month page with its new event dialog shown open: a title, a day from a folded calendar, a start time and length, guest emails as tags, and a day timeline that moves with the time and warns when the meeting clashes.
- Pro
A social scheduler's content calendar with its scheduling dialog shown open: a month to pick a day, best times plus any half hour, a zone that restates the time elsewhere, three channel switches, and a Schedule post button that drops a chip into the week behind it.
- Pro
A team chat inbox with a settings dialog shown open: a real table of notification kinds by channel with a switch in every cell, mixed-state column masters, reset and save, and a chip on the inbox that reports the saved count.
- Pro
Set Reminder Dialog
Time and schedulingA to-do list with its reminder dialog shown open: five quick chips, an inline calendar and a time in quarter hours, repeat and notify choices, and one plain sentence that always reads the choice back.