Coordinate Input

Latitude and longitude, accepting decimal degrees or DMS. A latitude above 90 is reported as "is this a longitude?" rather than "out of range" — swapped pairs are the most common coordinate bug there is.

src/components/ui/coordinate-input.tsx

About

From the component's own source, where it was written.

Latitude and longitude, accepting decimal degrees or DMS.

People paste coordinates from wherever they found them — 51.5074, -0.1278 from a URL, 51°30'26.6"N 0°07'39.9"W from a chart. Rejecting the second form means the user converts it by hand, which is exactly where a digit gets dropped. Both are parsed; the canonical decimal pair is what leaves.

A single field accepts a pasted pair and splits it, because a comma-separated pair is how coordinates travel and forcing two paste operations is a small cruelty.

Ranges are checked and, more usefully, so is the *ordering*: a latitude above 90 is almost always a longitude in the wrong box. Saying so is more helpful than "out of range", and swapped pairs are the most common coordinate bug there is.

Six decimal places is the display precision — about 11cm. More digits imply an accuracy no consumer GPS has.

Install

npx astralyx-ui add coordinate-input

Usage

import { CoordinateInput } from '@/components/ui/coordinate-input'

<CoordinateInput value={value} onValueChange={setValue} />

Composer

Change the props and the source below follows.

Props
tsx
<CoordinateInput value={value} onValueChange={setValue} />

Examples

Round-tripping a pair

API

Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.

CoordinateInput

Extends Omit<ComponentProps<'div'>, 'onChange' | 'value'>.

PropTypeDefaultDescription
valueCoordinate | null—{ lat, lng }. null while the fields do not parse to a valid pair.
onValueChange(value: Coordinate | null) => void——
size'sm' | 'md''md'—
disabledboolean——
copyablebooleantrue—
latitudeLabelReactNode'Latitude'—
longitudeLabelReactNode'Longitude'—
latitudePlaceholderstring'51.5074'—
longitudePlaceholderstring'-0.1278'—
copyLabelstring'Copy coordinates'—
invalidNoteReactNode'Not a coordinate'Shown when a field does not parse at all.
latitudeRangeNoteReactNode'Above 90° — is this a longitude?'Shown for a latitude past ±90 — usually a swapped pair.
longitudeRangeNoteReactNode'Beyond 180°'—

Functions

FunctionSignatureDescription
parseCoordinate(raw: string) => number | nullDecimal degrees, or degrees/minutes/seconds with an optional hemisphere.
parseCoordinatePair(raw: string) => Coordinate | nullSplits a pasted lat, lng pair on a comma or whitespace between the two.

Types

Coordinate

Latitude and longitude, accepting decimal degrees or DMS.

FieldTypeDescription
latnumber—
lngnumber—

Behaviour

TopicDetailDescription
input formatsdecimal or DMSBoth 51.5074 and 51°30'26.6"N parse. Rejecting the second means the user converts by hand, which is where a digit gets dropped.
pastesplits a pairPasting 51.5074, -0.1278 into either field fills both — a comma-separated pair is how coordinates travel.
precision6 placesAbout 11cm. More digits imply an accuracy no consumer GPS has.