Skip to content
NewYour data: charts, lists and meters that take your records
<GeoMiniMap />ReactMaps & trafficFree

Location cell

A world thumbnail with one point for table cells. Hover or focus it and a popover grows out of the point while the map inside zooms in on it.

View as Markdown
<GeoMiniMap />

Trymove the pointer down the location column, then click a map to pin its card.

Your data

Pass your place as location ({ lat, lon, label?, detail?, timeZone? }) and, for the distance row, a reference point as from. Without location the cell shows a demo location (Singapore). See Your data.

Playground

Change a prop and the component re-renders. Props marked remounts set an initial value, so the component starts over.

Loading <GeoMiniMap />
Props
sizelive
tonelive
zoomlive
sidelive
unitlive
defaultOpenremounts
React
<GeoMiniMap
  location={{
    lat: 35.6762,
    lon: 139.6503,
    label: "Tokyo",
    detail: "Sign-in from 203.0.113.88",
    timeZone: "Asia/Tokyo"
  }}
  from={{
    lat: 50.1109,
    lon: 8.6821,
    label: "Frankfurt"
  }}
  size="md"
  tone="accent"
  zoom={4}
  side="auto"
  unit="km"
/>

Installation

pnpm dlx shadcn@latest add @lumesec/geo-mini-map
First timeRegister the @lumesec registry once, or install by URL+

Adds @lumesec to your components.json:

pnpm dlx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json

Or skip the setup and install by URL:

npx shadcn@latest add https://elements.lumesec.ai/r/geo-mini-map.json

Usage

geo-mini-map-example.tsx
import { GeoMiniMap, type MiniMapLocation } from "@/components/lumesec/geo-mini-map";

const office = { lat: 50.1109, lon: 8.6821, label: "Frankfurt" };

export function SignInLocation({ location }: { location: MiniMapLocation }) {
  return <GeoMiniMap location={location} from={office} />;
}

Behaviour

A 96 × 48 world thumbnail with one point, sized for table cells and list rows.

Hover or focus it and a popover grows out of the point while the map inside dives toward it: finer land resolves outward from the point and a ring of dots pings where it lands. The place name, coordinates, local time and an optional distance appear as text. Thumbnails of one size share one baked lattice, so a table full of them stays light.

API reference

Props

Also accepts every prop of <button> (React.ComponentProps<"button">), spread onto the root element.

locationTypeMiniMapLocationDefaultSingapore (demo)

The place: { lat, lon, label?, detail?, timeZone? }. label titles the popover and starts the accessible name, detail is the line under it, and a valid IANA timeZone adds the local time. Missing fields are omitted.

fromTypeMiniMapReference

Reference point for the distance row: { lat, lon, label? }, read as 'From Frankfurt 7,406 km'. Without it the row is omitted.

openTypeboolean

Controlled popover state. Use with onOpenChange.

defaultOpenTypebooleanDefaultfalse

Popover state when uncontrolled.

onOpenChangeType(open: boolean) => void

Called when hover, focus, a click, Escape or another opening popover opens or closes this one.

sizeType"sm" | "md" | "lg"Default"md"

Thumbnail size: 72 × 36, 96 × 48 or 128 × 64 px, plus a 1 px border.

sideType"auto" | "top" | "bottom"Default"auto"

Where the popover opens. auto opens above and flips below when the card does not fit above and there is more room below.

zoomTypenumberDefault4

Zoom of the popover map, clamped to 2 to 6. At 4 the map shows about 90° of longitude around the point.

unitType"km" | "mi"Default"km"

Unit of the distance row and the scale bar.

toneType"accent" | "info" | "success" | "warning" | "destructive"Default"accent"

Colour of the point, the marker and its ring, for example warning for a sign-in from a new place.

Ref

ref points at the root HTMLButtonElement.

Keyboard

KeysAction
TabFocus the thumbnail. The popover opens at once and closes when focus leaves, unless it is pinned.
Enter / SpacePin the popover, or unpin and close it.
EscapeClose the most recently opened popover. Focus stays on the thumbnail.

Accessibility

  • The trigger is a native button with aria-expanded, aria-controls and aria-pressed for the pinned state.
  • Its accessible name is the place and its coordinates ('Tokyo, 35.6762° N, 139.6503° E'), so the cell makes sense without opening it. An aria-label you pass replaces it.
  • aria-describedby points at the popover's detail line and its local time and distance rows; ids you pass in aria-describedby are kept.
  • The popover is non-modal text in the top layer. It takes no focus and holds no controls.
  • Both canvases are aria-hidden. Every readable value (name, coordinates, time, distance, scale) is DOM text.
  • Focus shows a 2 px accent outline.
  • Reduced motion: the popover fades in over 120 ms at full size with the map already zoomed in, the text rows appear without sliding, numbers swap without rolling, and there is no resolution sweep or ring ping.

Theming

Styled with Tailwind classes on your shadcn theme tokens, so light and dark follow your theme. The accent comes from --lumesec. See Theming.

This component reads --card, --border, --popover, --popover-foreground, --foreground, --muted-foreground, --lumesec, --lumesec-glint, --lumesec-info, --lumesec-success, --lumesec-warning and --destructive.

Notes

  • Opening: the card grows out of the point on a spring (scale 0.04 to 1, with a slight overshoot). The map inside starts on the world and dives toward the point; finer land resolves outward from the point behind an uneven accent front, the point lands as a 4 px marker and a ring of dots pings around it. Closing shrinks the card back into the point on a faster spring.
  • Hover opens the popover after 120 ms; the pointer leaving both the thumbnail and the popover closes it after 150 ms. Focus opens it at once. A click, Enter or Space pins it, and pressing inside the popover pins it too. On touch, a tap toggles the pinned popover.
  • Only one unpinned popover is open per page: opening one closes the others. Pinned popovers stay until they are unpinned or closed with Escape. Pinning an open popover pings its point again.
  • The popover uses the Popover API (popover="manual"), so a table cell with overflow: hidden cannot clip it. It is centred over the point, kept 8 px inside the viewport, follows the thumbnail on scroll and resize, and closes when the thumbnail scrolls out of view. Without the Popover API it is a fixed card with z-index: 50.
  • The component renders the button and the popover as siblings. Clicks inside the popover do not bubble to row handlers around it.
  • Thumbnails of one size share a single baked lattice per pixel ratio and theme, so a long table draws one image per row. The zoom levels of a place are built once, while the hover delay runs, and cached for the page.
  • The local time is read after mount and formatted in the place's timeZone, never the viewer's. The scale bar gives a 1-2-5 distance at the point's latitude.
  • The land comes from the embedded world dataset at 0.5° resolution. Some coastal cities, Singapore among them, fall on water cells, so the marker can sit just off the dotted coast.

Was this page helpful?