Loading playground
Overview
LocationCard is the card for a single physical location. It carries the store name, image, a single-line address, a pre-formatted distance string, an OpeningStatus summary, up to a handful of feature pills (drive-through, accessibility, parking), and up to three action buttons: Navigate, Call, and Details.
The variant prop picks the layout:
listis the row layout for store directories and list panels alongside a map. The card body wraps in an anchor pointing atdetailsUrl(so tapping anywhere on the body opens the detail page), and the action buttons stay outside the wrapping anchor to keep the HTML valid. SetbodyAsLink={false}to keep the body clickable for selection only without making it a link.mapPopupis the square popup that sits inside a map marker's info window. The image renders at a fixed1/1aspect ratio and the action buttons stretch to the popup's width.
Every interactive action emits the location's id so the parent map or list view can correlate the click without re-deriving identity from props.
Key Business & UX Benefits
- Two variants from one component keep map popups and list rows visually consistent, so shoppers see the same store information whether they tap a marker or scan the list.
- Tap-anywhere navigation on the
listbody (whendetailsUrlis set) reduces the tap target precision a shopper needs on mobile, lifting click-through to the detail page. - Wiring Navigate, Call, and Details directly as anchors (with
tel:for phone andtarget="_blank"for maps) means iOS and Android handle the actions natively instead of going through JavaScript handlers that can break on slow networks. - Stable
idon every event lets the parent map view sync selection state without re-deriving identity from the address string.
Feature List
- Two layouts (`list`, `mapPopup`) cover store directories and map popups from one component
- Composes `OpeningStatus` so each card carries the current open/closed state and next state-change time
- Up to three action buttons (Navigate, Call, Details) wired as anchors so iOS and Android handle them natively
- `bodyAsLink` opts the `list` card out of body-wide linking when the parent only wants to handle selection
- Up to three feature pills via `FeaturePillList` for callouts like drive-through, accessibility, or parking
- Every action emits the location `id`, so the parent map or list view can correlate clicks without prop-derived identity
- Image falls back to a flat placeholder when absent, so missing-image stores don't break the row alignment
API Reference
| Prop | Default | Type |
|---|---|---|
idrequired | stringStable identifier — emitted with all events; used by parent for selection. | |
variantrequired | "list" | "mapPopup"Layout variant. | |
namerequired | stringDisplay name. | |
image | Location image. Falls back to Media's built-in placeholder when absent. | |
address | stringPre-formatted single-line address. Locale formatting is the consumer's concern. | |
distance | stringPre-formatted distance string (e.g. '1,2 km'). | |
openingHours | OpeningHours { timeZone, schedule, exceptions }Schedule + IANA timezone — drives the OpeningStatus child. | |
features | FeaturePillItem[] { icon, label }Up to ~3 inline feature pills (e.g. drive-through, accessibility). | |
navigateUrl | stringWhen set, renders the Navigate button as an anchor pointing here. | |
phone | stringWhen set, renders the Call button as a | |
detailsUrl | stringWhen set, renders the Details button as an anchor.
For | |
bodyAsLink | booleanWhen false, the card body never renders as an anchor — even when
|
| Event | Type |
|---|---|
select | (event: "select", id: string): void |
details | (event: "details", id: string): void |
navigate | (event: "navigate", id: string): void |
call | (event: "call", id: string): void |
Related
OpeningStatus: the open/closed summary rendered inside each card.OpeningHoursWeeklyTable: the full weekly schedule for the detail page this card links to.OpeningHourstype: the shape theopeningHoursprop expects.Mediatype: the shape theimageprop expects.