Skip to content
Neon UI
Esc
navigateopen⌘Jpreview
On this page

RegionSelect

Server location picker — an interactive dot-matrix world map synced with an accessible select.

RegionSelect turns the region dropdown from project creation into the map itself. Every datacenter is a live marker on a dot-matrix world map: hover lifts a label pill with the city and region id, click selects, and the chosen marker glows primary with a slow ping halo. A floating region card mirrors the selection — name, mono region id, and your measured round-trip when latencies is provided — and the select underneath is the same input — so keyboard and screen-reader users get the full flow without ever touching the map. The land bitmap draws once to a canvas in the current theme’s ink, not thousands of DOM nodes.

Region

Region

AWS Europe Central 1 (Frankfurt)

aws-eu-central-1 · ping: 92 ms

Select the region closest to your application.

Install

npx shadcn@latest add https://ui.neon.com/r/region-select.json

Usage

import { RegionSelect } from "@/components/neon-ui/region-select";

<RegionSelect
  regions={[
    {
      id: "aws-us-east-1",
      name: "US East 1 (N. Virginia)",
      provider: "AWS",
      lat: 38.9,
      lng: -77.4,
    },
    {
      id: "aws-eu-central-1",
      name: "Europe Central 1 (Frankfurt)",
      provider: "AWS",
      lat: 50.11,
      lng: 8.68,
    },
  ]}
  value={region}
  onValueChange={setRegion}
/>;

Wiring to Neon

A server component turns the active regions into ServerRegions:

import { createNeonClient } from "@/lib/neon-client";

const neon = createNeonClient(process.env.NEON_API_KEY);
const { data } = await neon.regions.list();
// set orgId on the client to scope this to one organization's regions

const regions = (data ?? [])
  .filter((region) => region.geo_lat && region.geo_long)
  .map((region) => ({
    id: region.region_id,
    name: region.name,
    provider: region.region_id.split("-")[0].toUpperCase(),
    lat: Number(region.geo_lat),
    lng: Number(region.geo_long),
  }));

Coordinates come back as strings and are empty when Neon does not know them, so filter before mapping or the marker lands at 0,0. default: true marks the region new projects use, which makes a sensible defaultValue. Selection is client state, so wire onValueChange in a client wrapper.

Props

PropType
regions?ServerRegion[]

Regions to plot and list; each needs an id, name, and lat/lng. Order drives the select.

TypeServerRegion[]
value?string

Controlled selected region id.

Typestring
defaultValue?string

Uncontrolled initial region id.

Typestring
onValueChange?(value: string) => void

Fires on marker click or select change.

Type(value: string) => void
placeholder?string

Select placeholder before a region is chosen.

Typestring
Default"Select region"
hideSelect?boolean

Hide the select under the map; markers become the only input.

Typeboolean
hideCard?boolean

Hide the floating region card on the map.

Typeboolean
cardSuffix?ReactNode

Extra content inside the region card, e.g. a latency badge.

TypeReactNode
latencies?Record<string, number | null>

Measured round-trips by region id (e.g. from useRegionPing); the selected region's ping folds into the card's mono line.

TypeRecord<string, number | null>

ServerRegion

PropType
id?string

Region id, e.g. "aws-us-east-1". Shown mono in the marker pill.

Typestring
name?string

Human-readable name, e.g. "US East 1 (N. Virginia)".

Typestring
provider?string

Optional provider prefix for labels, e.g. "AWS".

Typestring
lat?number

Datacenter latitude.

Typenumber
lng?number

Datacenter longitude.

Typenumber
disabled?boolean

Unavailable region; marker and option render dimmed.

Typeboolean

Accessibility

  • Markers are real buttons with aria-pressed and full labels; the hover pill is presentational.
  • The select is the same input, so the complete keyboard and screen-reader flow needs no map interaction. Keep it visible unless another accessible input drives the value.
  • The ping halo on the selected marker is static under prefers-reduced-motion; the map canvas is decorative (aria-hidden).

Notes

  • The map is Natural Earth 110m land sampled onto a 192×69 equirectangular grid (Antarctica clipped) and shipped as a compact hex bitmap — no map library, no fetch.
  • The canvas re-inks itself on theme flips by watching the root element’s class, so the dots always match text-muted-foreground.