@mmerlone/react-tz-globepicker
v0.2.0
Published
Interactive 3D globe component for timezone selection with React
Maintainers
Readme
react-tz-globepicker
Interactive globe picker for React applications that need timezone selection, timezone visualization, or a compact world-time UI.

Try the interactive online demo.
Features
- Drag-to-rotate globe interaction with wheel zoom
- Clickable timezone markers with optional tooltips
- Animated fly-to transitions when the selected timezone changes
- Multiple timezone boundary modes:
none,nautic,etc-gmt, andiana - Bundled geodata with no extra runtime setup
- Custom colors, custom backgrounds, controlled zoom, and imperative
refmethods - Framework-agnostic styling: no CSS framework required
Installation
pnpm add @mmerlone/react-tz-globepicker
# or
npm install @mmerlone/react-tz-globepicker
# or
yarn add @mmerlone/react-tz-globepickerPeer dependencies
react^19.0.0react-dom^19.0.0
Quick Start
import * as React from "react";
import { TzGlobePicker } from "@mmerlone/react-tz-globepicker";
export function App(): React.ReactElement {
const [timezone, setTimezone] = React.useState<string | null>(
"America/New_York",
);
return (
<TzGlobePicker
timezone={timezone}
size={400}
onSelect={setTimezone}
showMarkers
showTooltips
showTZBoundaries="etc-gmt"
showCountryBorders
/>
);
}Next.js And Client Components
TzGlobePicker is a client component. In Next.js App Router, use it from a file that starts with:
"use client";Boundary Modes
The showTZBoundaries prop controls how the currently selected timezone is highlighted.
| Mode | Best for | Behavior |
| --------- | ----------------------------------- | ------------------------------------------------------------- |
| none | Minimal UI | No boundary highlight |
| nautic | Fastest, offset-style visualization | Uses a 15-degree longitude band based on canonical UTC offset |
| etc-gmt | Good default | Uses merged offset-region geometries |
| iana | Highest detail | Uses timezone-level IANA boundary data |
Preview
Nautic (nautic)

ETC/GMT (etc-gmt)

IANA (iana)

Common Patterns
Use Custom Marker Sets
If you already know which timezones should be selectable, build a marker list once and pass it in. A non-empty markers array will render markers even if showMarkers is omitted.
import * as React from "react";
import { TzGlobePicker, buildMarkerList } from "@mmerlone/react-tz-globepicker";
const allowedTimezones = [
"America/New_York",
"Europe/London",
"Asia/Tokyo",
"Australia/Sydney",
];
const markers = buildMarkerList(allowedTimezones);
export function TimezonePicker(): React.ReactElement {
const [timezone, setTimezone] = React.useState<string | null>(
"America/New_York",
);
return (
<TzGlobePicker
timezone={timezone}
onSelect={setTimezone}
markers={markers}
showTooltips
zoomMarkers
showTZBoundaries="etc-gmt"
showCountryBorders
size={360}
/>
);
}Use The Built-In Background
import * as React from "react";
import { SpaceBackground, TzGlobePicker } from "@mmerlone/react-tz-globepicker";
export function App(): React.ReactElement {
return (
<TzGlobePicker
timezone="America/New_York"
size={400}
onSelect={(tz) => console.log(tz)}
showMarkers
background={<SpaceBackground />}
/>
);
}Control Zoom Externally
import * as React from "react";
import { TzGlobePicker } from "@mmerlone/react-tz-globepicker";
export function App(): React.ReactElement {
const [zoom, setZoom] = React.useState(1);
return (
<TzGlobePicker
timezone="Europe/London"
zoom={zoom}
onZoomChange={setZoom}
minZoom={1}
maxZoom={5}
showMarkers
size={380}
/>
);
}Use The Imperative Ref API
import * as React from "react";
import {
TzGlobePicker,
type TzGlobePickerRef,
} from "@mmerlone/react-tz-globepicker";
export function App(): React.ReactElement {
const globeRef = React.useRef<TzGlobePickerRef>(null);
return (
<div>
<button
type="button"
onClick={() => globeRef.current?.flyTo("Asia/Tokyo")}
>
Fly To Tokyo
</button>
<button type="button" onClick={() => globeRef.current?.reset()}>
Reset
</button>
<TzGlobePicker
ref={globeRef}
timezone="America/New_York"
showMarkers
size={360}
/>
</div>
);
}API Reference
TzGlobePicker Props
| Prop | Type | Default | Description |
| -------------------- | --------------------------------------------------- | ----------- | ---------------------------------------------------------------- |
| timezone | string \| null | null | Selected IANA timezone ID such as "America/New_York" |
| size | number | 250 | Globe diameter in pixels |
| onSelect | (timezone: string) => void | undefined | Called when a marker is clicked |
| showMarkers | boolean | false | Renders the built-in canonical marker set when true |
| showTooltips | boolean | false | Shows marker tooltips on hover |
| zoomMarkers | boolean | false | Scales marker size with zoom |
| minZoom | number | 1 | Minimum zoom multiplier |
| maxZoom | number | 5 | Maximum zoom multiplier |
| initialZoom | number | 1 | Initial zoom multiplier |
| zoom | number | undefined | Controlled zoom value |
| onZoomChange | (zoom: number) => void | undefined | Called when zoom changes |
| showTZBoundaries | TzBoundaryMode | "none" | Boundary visualization mode |
| showCountryBorders | boolean | false | Draws country borders |
| showGeographic | boolean | false | Draws equator, tropics, polar circles, and IDL |
| background | string \| React.ReactElement \| null \| undefined | undefined | CSS background string or a background element |
| markers | MarkerEntry[] | undefined | Explicit marker list; a non-empty array enables marker rendering |
| colors | Partial<GlobePalette> | undefined | Partial palette override |
| style | React.CSSProperties | undefined | Inline styles for the outer container |
| className | string | undefined | Class name for the outer container |
| simulatedDate | Date | undefined | Overrides sun position calculations for testing and demos |
TzGlobePickerRef
type TzGlobePickerRef = {
reset: () => void;
flyTo: (timezone: string, resetZoom?: boolean) => void;
};Exported Components
import {
ResetButton,
SpaceBackground,
TzGlobePicker,
} from "@mmerlone/react-tz-globepicker";TzGlobePicker: main interactive globe componentSpaceBackground: reusable gradient background componentResetButton: small reset control used internally and available for custom UIs
Exported Types
import type {
Coordinate,
GeoData,
GlobePalette,
GlobeState,
LatLng,
MarkerEntry,
RenderFn,
Rotation,
TzBoundaryMode,
TzGlobePickerProps,
TzGlobePickerRef,
} from "@mmerlone/react-tz-globepicker";Exported Constants
import {
CLICK_THRESHOLD,
COLORS,
DRAG_SENSITIVITY,
FLY_DURATION,
GRATICULE_STEP,
HIT_RADIUS,
INERTIA_FRICTION,
INERTIA_MIN_VELOCITY,
MAX_BOUNDARY_AREA,
MAX_LATITUDE,
MAX_ZOOM,
MIN_ZOOM,
TILT,
TZ_BOUNDARY_MODES,
ZOOM_SENSITIVITY,
} from "@mmerlone/react-tz-globepicker";Exported Utilities
import {
buildMarkerList,
CANONICAL_MARKERS,
etcToOffset,
formatUtcOffset,
getCanonicalMarkers,
getSubsolarPoint,
getTimezoneCenter,
getUtcOffsetHour,
getUtcOffsetMinutes,
IANA_TZ_DATA,
ianaToEtc,
mapToCanonicalTz,
offsetKeyFromEtc,
TIMEZONE_COORDINATES,
utcOffsetToLongitude,
useGlobeState,
} from "@mmerlone/react-tz-globepicker";Marker Utilities
buildMarkerList(allowed?)
Builds marker entries from the bundled timezone coordinate map.
import { buildMarkerList } from "@mmerlone/react-tz-globepicker";
const allMarkers = buildMarkerList();
const subset = buildMarkerList(["America/New_York", "Europe/London"]);getCanonicalMarkers()
Returns the curated built-in canonical marker list.
import { getCanonicalMarkers } from "@mmerlone/react-tz-globepicker";
const markers = getCanonicalMarkers();CANONICAL_MARKERS
Prebuilt marker array that works well as a lightweight default.
import {
CANONICAL_MARKERS,
TzGlobePicker,
} from "@mmerlone/react-tz-globepicker";
<TzGlobePicker markers={CANONICAL_MARKERS} />;Timezone Utilities
TIMEZONE_COORDINATES
Map from IANA timezone ID to approximate [latitude, longitude].
import { TIMEZONE_COORDINATES } from "@mmerlone/react-tz-globepicker";
const [lat, lng] = TIMEZONE_COORDINATES["America/New_York"] ?? [0, 0];getTimezoneCenter(timezone)
Returns an approximate [latitude, longitude] center, falling back to [0, 0] for unknown zones.
import { getTimezoneCenter } from "@mmerlone/react-tz-globepicker";
const [lat, lng] = getTimezoneCenter("America/Sao_Paulo");getUtcOffsetMinutes(timezone) and getUtcOffsetHour(timezone)
Current UTC offset based on Intl.
import {
getUtcOffsetHour,
getUtcOffsetMinutes,
} from "@mmerlone/react-tz-globepicker";
const minutes = getUtcOffsetMinutes("America/New_York");
const hours = getUtcOffsetHour("Asia/Kolkata");mapToCanonicalTz(timezone)
Maps an IANA timezone to the package's canonical timezone region set.
import { mapToCanonicalTz } from "@mmerlone/react-tz-globepicker";
const canonical = mapToCanonicalTz("America/Indiana/Indianapolis");ianaToEtc(ianaTimezone)
Returns the canonical offset key string used by the package, such as UTC-05:00.
import { ianaToEtc } from "@mmerlone/react-tz-globepicker";
const offsetKey = ianaToEtc("America/New_York");offsetKeyFromEtc(etcTimezone)
Normalizes Etc/GMT, GMT, or UTC-style inputs into canonical UTC+/-HH:MM keys.
import { offsetKeyFromEtc } from "@mmerlone/react-tz-globepicker";
offsetKeyFromEtc("Etc/GMT+5"); // "UTC-05:00"
offsetKeyFromEtc("GMT+05:30"); // "UTC+05:30"etcToOffset(etcTimezone)
Returns an object containing the normalized ISO-style offset key.
import { etcToOffset } from "@mmerlone/react-tz-globepicker";
const normalized = etcToOffset("Etc/GMT+5");
// { isoKey: "UTC-05:00" }utcOffsetToLongitude(offsetHours)
Converts an hour offset to the center longitude of the corresponding offset band.
import { utcOffsetToLongitude } from "@mmerlone/react-tz-globepicker";
const longitude = utcOffsetToLongitude(-5); // -75IANA_TZ_DATA
Array of supported canonical IANA timezone identifiers.
import { IANA_TZ_DATA } from "@mmerlone/react-tz-globepicker";
const firstTimezone = IANA_TZ_DATA[0];Advanced Hook
useGlobeState
This hook is exported for advanced integrations. It is not a simple app-level helper; it expects internal rendering refs and controller options similar to the library internals.
Palette Customization
The colors prop accepts a partial GlobePalette:
import * as React from "react";
import { TzGlobePicker } from "@mmerlone/react-tz-globepicker";
export function App(): React.ReactElement {
return (
<TzGlobePicker
timezone="Europe/London"
showMarkers
colors={{
ocean: "#001f3f",
land: "#0b6e4f",
selectedMarker: "#ff6b35",
highlightFill: "rgba(255, 107, 53, 0.28)",
}}
/>
);
}Data Loading
The package ships with bundled timezone and country data. You do not need to fetch any extra assets in your application.
Regenerating Globe Data
pnpm gen:globeThis regenerates the artifacts in src/data/, including split IANA and ETC/GMT geometry files.
Development
pnpm install
pnpm demo
pnpm lint
pnpm type-check
pnpm format
pnpm format:check
pnpm gen:globeData Sources
License
MIT
