shadcn.io is not affiliated with official shadcn/ui
Location Picker Dialog Block for React
A courier's pickup dialog shown open: a search field with Saved, Recent and Nearby places in an inline list, a drawn street map with a pin you drop or move with the arrow keys, and a latitude and longitude readout.
Installation
Overview
Let people say where a parcel is collected by pointing at it, with this location picker dialog for React with Base UI. It opens from the Book a pickup page of Parcelmoor, a same-day courier: the page's header holds an outline Pick on map Button, and the booking form, a Pickup field, a Drop-off field and a row of time chips, is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The dialog has a search Input with its suggestions in an inline Listbox, grouped as Saved, Recent and Nearby, and beside it (above the list on a phone) a street map drawn in SVG with a river, a street grid and two parks. Press the map to drop the pin, or focus it and move the pin with the arrow keys, 8 units a step and 32 with Shift; choosing a place moves the pin to it. A readout works out the latitude and longitude and names the nearest place. Confirm pickup, the only Shine Button, writes the place and its coordinates into the Pickup field. For preview the dialog is drawn open in place when the page loads; the header button opens the real Dialog, with the same search, pin and list. For couriers, delivery, repair and rental apps, and any form that needs a place.
FAQ
Why is the dialog already open, and what do I keep?
So you can see it without a click. On load the dialog is a copy drawn in place over the booking form: a native dialog element that isn't modal, so nothing is trapped, hidden or focused, and the page around the preview keeps working. The Pick on map button opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same PickerFields component and share the block's state, so a pin dropped in the copy is where it sits in the real one. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.
How do I place the pin without a mouse?
The map is one focusable control named Street map. With it focused the arrow keys move the pin 8 units, and Shift with an arrow moves it 32; the pin stays inside the map. Pressing the map with a pointer drops the pin under it, and Enter or Space on the focused map do nothing so a keyboard user never drops it by accident. Choosing a place in the list, with the mouse, or with the arrow keys and Enter after a search, is the other route, and Enter in the search field takes the top match. Moving the pin by keys is not announced on every step; the readout under the map shows the coordinates, and the polite message speaks when you drop the pin or pick a place.
Where do the coordinates come from?
They are worked out, not looked up. The map has a typed grid: the top start corner is 51.5200, -0.1140 and one map unit is 0.00007 degrees of latitude and 0.00009 of longitude, so the pin's position gives its latitude and longitude, shown to four decimals. The nearest place is the typed place with the smallest distance to the pin. The streets and places are invented, and the grid constants and PLACES are at the top of the file; in your app replace them with a geocoder and a map library, and read the pin from its click event.
Why is there no Use my location button?
It would need the browser's Geolocation permission, and a demo should not ask for it. Nothing here reads the device. If you add it, call navigator.geolocation.getCurrentPosition from the button's click handler (never on load), handle a refusal in words, and move the pin to the result the same way a chosen place does.
Is the list accessible from the keyboard?
Yes. The search field is labelled, the list is a listbox named Places, and the rows are options with a check on the chosen one. Down arrow in the search field moves into the list. The real dialog is named by its title and described by its sentence, focus starts in the search and stays inside until the dialog closes, and Escape, Cancel and the close button return focus to Pick on map. The trigger is passed to DialogTrigger through render, and the dialog is controlled with open and onOpenChange. The copy shown on load moves no focus; Escape inside it, Cancel and its close button close it and put focus on the button.
What stays local in the demo, and how do I wire it up?
All of it. Nothing is booked, searched or sent: the places are typed, the search filters them in the tab, and the only thing that leaves the dialog is the place and coordinates that Confirm pickup writes into the drawn Pickup field, with a polite message saying nothing was booked. In your app give confirm your own write-back (a form value, a booking request) and feed the list from your geocoder.
How does it look on a phone?
The copy shown on load docks to the foot of the page as a bottom sheet: the search first, then the map at its full width, then the list in a box that scrolls on its own, with the Cancel and Confirm pickup buttons pinned below. The list keeps one height whatever you type, and an empty search shows a message in the same box. The real dialog keeps the Dialog's own phone layout: a sheet stuck to the bottom of the screen, scrolling inside.
Related
- Pro
Address Autocomplete Dialog
Pickers and searchA meal-kit delivery page with its address dialog shown open: typing filters eight addresses of an invented town into an inline list you can arrow through, a choice fills four editable fields, and Enter it manually offers the same four, empty.
- Pro
Time Zone Picker Dialog
Time and schedulingA preferences page with its time zone dialog shown open: a search over 14 zones in four regions, each row with its city, UTC offset and the time there at one typed moment, a button that reads this device's zone on a press, and the chosen zone printed back on the page.
- Pro
A homeware shop's shipping dialog shown open: four delivery methods with arrival dates counted in business days from a fixed order date, prices in whole cents, a free-shipping bar and a button that names the choice.
- Pro
A furniture shop's order sheet shown open: a five-step delivery timeline with days and times worked out from a fixed today, the delivery window drawn on a track with its estimate, and the scans of any step you press.
- Pro
Add Card Dialog
Payments and plansA transit wallet's payment methods page with its add-card dialog shown open: a card drawn in greys that fills in as you type, a number that groups itself and names its network, checks on the number, expiry and code, and an Add card button that keeps only the last four digits.
- Pro
Add Profile Dialog
Account and securityA newsletter's writers page with its byline composer shown open: a name, what they write, a 120 character bio, a mark from six drawn glyphs or initials and a switch, beside a card that shows the byline as it will print.