Skip to content
SLICES / TECHNICAL FOLIO Nº 001FULL-STACK ASSEMBLIES — OPEN SOURCE

Headless / Location

Find and confirm an address

Build address search using the selected address and geocoder capabilities.

50 public parts · 4examples

@slices.sh/geocoder/headlessView as Markdown ↗

Your design. Our behavior.

Explore the tree to see what each part controls. Gates reveal the relevant state; roots outline their scope.

Behavior / inputGateGenericRenderer · not headlessScope
COMPONENT ANATOMYHover · focus · tap
ONE POSSIBLE DESIGNStatic preview

Address.Root · Scope

Address.RootAn address field.

Installation

Choose what your component needs. Run these commands in an initialized Next.js app.

0

Before you start

The steps below run in a Next.js app with shadcn set up (it has a components.json). In an existing Next.js app, such as one from create-next-app, set shadcn up first:

npx shadcn@latest init -t next -b base -p nova

Or start fresh: the slices CLI creates the app and sets it up.

npx slices.sh install
1

Install the service registry

Adds services/index.ts, which import "@/services" loads. A provider setup writes the same file, so skip this if your app has one.

npx add services
2

Install the headless library

npm

Add the React parts to your app, then compose them with your own elements.

npm install @slices.sh/geocoder@^0.1.3

Import from @slices.sh/geocoder/headless.

3

Install the service

Connect the parts to a provider. Skip this step if this service is already configured in your app.

Provider
npx add geocoder.photon

Adds service configuration and API routes to your app, with the provider dependencies. For a headless composition, add import "@/services" after "use client".

The slices CLI installs the service and provisions its required resources in one command.

Start small

Parts bring the behavior. Use their default elements, or supply your own with render.

example.tsx
"use client"// services/index.ts comes from https://slices.sh/r/services.json (or any provider setup)import "@/services"import { Address } from "@slices.sh/geocoder/headless"export function Example() {  return (    <Address.Root country="FR">      <Address.Label>Address</Address.Label>      <Address.Input />      <Address.Popup>        <Address.Suggestions>          <Address.Items>            <Address.Suggestion>              {({ primary, secondary }) => (                <span>                  {primary} · {secondary}                </span>              )}            </Address.Suggestion>          </Address.Items>        </Address.Suggestions>        <Address.Attribution />      </Address.Popup>      <Address.Value name="address" />    </Address.Root>  )}

Selection, keyboard navigation and the structured value stay connected.

API reference

Every public part used by this experience is listed below. Gates render children without adding an element. Element parts accept native element props and render; function children receive the state declared in their props. Scopes provide context rather than a visual element.

Address.Rootscope

An address field. The popup, its keyboard and its ARIA are Base UI's Autocomplete rather than this family's: the hand-rolled version this replaces latched shut after a blur, an Escape or a selection and never showed a suggestion again. Autocomplete and not Combobox because the value has to be allowed to be anything — plenty of real addresses are in no database, which is this family's whole argument — and `filter={null}` because the filtering is the provider's. Base UI's own context holds the open state and the highlight. That is a primitive's internal state rather than a slices concern, the same relationship `lib/part` already has with `use-render`, and the hooks below still own one thing each. → docs/rules/one-hook-one-concern.md

Props

18 documented props

Address.Root props
PropTypeDefault
layout
"card" | "box" | "form"—
fields
readonly AddressDetailFieldName[]—
markOptional
boolean—
scope
AutofillScope—
country

Bias towards a country, as ISO 3166-1 alpha-2.

string—
countries
readonly string[] | null—
countryScope
"bias" | "restrict"—
enabled

Left out or true: required, and a missing geocoder throws. "optional": renders its children and the field is a manual address form: the street box is a plain input, the search parts render nothing, and Entry, Field, Lines, Value and Save keep working. false: off, which looks the same. "reverse": requires a geocoder that can turn a point into an address (otherwise UseMyLocation renders nothing).

Enabled—
config

The geocoder config, "default" when left out.

string—
language

The language the names come back in. Absent asks with the browser's own.

string—
enterPicksFirst

Enter selects the first suggestion only when explicitly enabled.

booleanfalse
undoWindow
number—
near

Bias towards a place. "Use my location" supplies one as soon as it is allowed.

Point—
kinds

Only these kinds, where a form wants nothing coarser than a street.

AddressKind[]—
recent
RecentAddressSource—
recentStorageKey
string—
initial
Address—
children

Content rendered inside this part.

ReactNode—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/address-root.tsx

Address.UndoScopecontent · <div>

No document listener: another address or another form keeps its own undo history.

Required scope

Address.UndoScope must be inside <Address.Root>.

Props

2 documented props · Native <div> attributes supported

Address.UndoScope props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/undo-scope.tsx

Address.Labelcontent · <label>

The visible label for the box, or for one of the fields beside it. A visible one, not an `aria-label`: a label somebody can click is a bigger target, which is the whole point on a phone.

Required scope

Address fields must be inside <Address.Root>.

Address.Label must be inside <Address.Root>.

Props

3 documented props · Native <label> attributes supported

Address.Label props
PropTypeDefault
field
AddressDetailFieldName—
children

Content rendered inside this part.

ReactNode | ((state: { optional: boolean; kind: string | null }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/label.tsx

Address.Inputinput · <input>

The box itself, and the street line of the address. `role`, `aria-expanded`, `aria-controls` and `aria-activedescendant` are the primitive's now. What is set here is what the primitive has no opinion about: the autofill token, so the browser's own one-tap address fill works and SC 1.3.5 is satisfied; the keyboard hints a phone reads; and the link to the notes underneath, which have no other way to be heard.

Required scope

Address.Input must be inside <Address.Root>.

Props

2 documented props · Native <input> attributes supported

Address.Input props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/address-input.tsx

Address.Clearaction · <button>

Empties the box. The primitive's own Clear, which keeps focus in the field rather than dropping it to the body, and hides itself while there is nothing to clear. Emptying the box is an ordinary value change as far as this family is concerned, so there is nothing to do here but let it through.

Props

2 documented props · Native <button> attributes supported

Address.Clear props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/clear.tsx

Address.Popupcontent · <div>

Where the suggestions appear. A positioned layer rather than an absolutely-positioned block, which is what buys the three things the hand-rolled list did not have: it flips above the box when there is no room below, it publishes `--anchor-width` and `--available-height` for the skin to size itself by, and it scrolls the highlighted option into view — browsers do not scroll to an `aria-activedescendant`, so somebody has to.

Required scope

Address.Popup must be inside <Address.Root>.

Props

2 documented props · Native <div> attributes supported

Address.Popup props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/popup.tsx

Address.Suggestionscontent · <ul>

The list. Mounted for as long as the popup is, so `aria-controls` on the box names something that exists whenever the box says it is expanded. The element itself comes from the caller — a neutral layer renders no host element — and `role="listbox"` is the primitive's.

Required scope

Address.Suggestions must be inside <Address.Root>.

Props

2 documented props · Native <ul> attributes supported

Address.Suggestions props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/suggestions.tsx

Address.Recentcontent · <li>

A non-selectable heading inside the autocomplete list, never above the field.

Required scope

Address.Recent must be inside <Address.Root>.

Props

2 documented props · Native <li> attributes supported

Address.Recent props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/recent.tsx

Address.RecentItemsscope

Only while the street is empty and nothing is chosen. Recent is the non-selectable heading inside the list, RecentItems repeats its children per saved address, RecentAddress is a button that fills the whole address and returns focus to the street, and RecentSeparator divides them from live suggestions.

Required scope

Address.RecentItems must be inside <Address.Root>.

Props

1 documented props

Address.RecentItems props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/recent-items.tsx

Address.RecentAddressaction · <button>

Only while the street is empty and nothing is chosen. Recent is the non-selectable heading inside the list, RecentItems repeats its children per saved address, RecentAddress is a button that fills the whole address and returns focus to the street, and RecentSeparator divides them from live suggestions.

Required scope

Address.RecentAddress must be inside <Address.Root>.

Address.RecentAddress must be inside <Address.RecentItems>.

Props

2 documented props · Native <button> attributes supported

Address.RecentAddress props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/recent-address.tsx

Address.RecentSeparatorcontent · <li>

Only while the street is empty and nothing is chosen. Recent is the non-selectable heading inside the list, RecentItems repeats its children per saved address, RecentAddress is a button that fills the whole address and returns focus to the street, and RecentSeparator divides them from live suggestions.

Required scope

Address.RecentSeparator must be inside <Address.Root>.

Props

2 documented props · Native <li> attributes supported

Address.RecentSeparator props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/recent-separator.tsx

Address.Itemsscope

Each suggestion in its own scope.

Required scope

Address.Items must be inside <Address.Root>.

Props

1 documented props

Address.Items props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/suggestion-items.tsx

Address.Suggestioncontent · <li>

One option. The element comes from the caller, because a neutral layer renders no host element, and `role="option"` is the primitive's. `aria-selected` is not: the primitive leaves it off because its list is not a selection. That attribute is load-bearing: Chrome plus VoiceOver announces a moving `aria-activedescendant` only when the option it names carries `aria-selected="true"`, so without it the box is silent on the most common pairing there is.

Required scope

Address.Suggestion must be inside <Address.Items>.

Address.Suggestion must be inside <Address.Root>.

Props

2 documented props · Native <li> attributes supported

Address.Suggestion props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: SuggestionState) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/suggestion.tsx

Address.Matchcontent · <span>

The matched text is styled by a role; neither query nor provider text becomes HTML.

Required scope

Address.Match must be inside <Address.Items>.

Address.Match must be inside <Address.Root>.

Props

3 documented props · Native <span> attributes supported

Address.Match props
PropTypeDefault
fieldRequired
"primary" | "secondary"—
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/match.tsx

Address.Notescontent · <div>

Everything the box has to say, in one place that is always there. One region, because the box's `aria-describedby` has to name an element that exists even when there is nothing to say — and because two live regions announcing at once is how a screen reader ends up reading the result count over the error. WCAG 2.2 SC 4.1.3. Whatever a skin does to it, it must never be `display: none`, `hidden` or `aria-hidden`, not even while it is empty: a region that appears in the same frame as its first words is a region several screen readers say nothing about. Mounted, rendered, and empty is the only shape that announces reliably — which is why everything the field has to say goes in here rather than beside the control it is about.

Required scope

Address.Notes must be inside <Address.Root>.

Props

2 documented props · Native <div> attributes supported

Address.Notes props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/notes.tsx

Address.Searchinggate

A question has been asked and not yet answered.

Required scope

Address.Searching must be inside <Address.Root>.

Props

1 documented props

Address.Searching props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/searching.tsx

Address.Resolvinggate

Gates and triggers for each answer. Searching: a question asked and not answered. Resolving: the optional detail lookup after a choice. TooShort: under the three-character floor, children get { least }. NoMatches: the provider answered with nothing. Failed gets { error }, the GeocoderErrorSlug, so a throttle and an outage are not one sentence. Retry appears only after a refusal and asks again.

Required scope

Address.Resolving must be inside <Address.Root>.

Props

1 documented props

Address.Resolving props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/resolving.tsx

Address.TooShortgate

Typed, but not enough of it to ask yet. The one state with nothing on screen and a reason for it, which is exactly the message no markup can carry and a screen reader therefore never hears unless somebody says it.

Required scope

Address options must be inside <Address.Root>.

Address.TooShort must be inside <Address.Root>.

Props

1 documented props

Address.TooShort props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { least: number }) => ReactNode)—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/too-short.tsx

Address.NoMatchesgate

The geocoder found nothing. Which is not the end of the road: the fields are there to be typed into, because a geocoder that has never heard of somebody's address must not be the reason they cannot check out.

Required scope

Address options must be inside <Address.Root>.

Address.NoMatches must be inside <Address.Root>.

Props

1 documented props

Address.NoMatches props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/no-matches.tsx

Address.ResultCountcontent · <span>

How many suggestions there are, said out loud. A screen reader hears the highlighted option read out and is told nothing about how many others there are, or that a query is still too short to have asked. The markup does not carry either, which is why this part exists and why `Address.TooShort` has words of its own. WCAG 2.2 SC 4.1.3.

Required scope

Address.ResultCount must be inside <Address.Root>.

Props

2 documented props · Native <span> attributes supported

Address.ResultCount props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: CountState) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/result-count.tsx

Address.Failedcontent · <p>

The geocoder refused, with the reason. The reason is handed over rather than flattened into one sentence: telling somebody the service is down when they have been throttled, and there is a Retry beside it, is a small lie. → docs/rules/capability-honesty.md

Required scope

Address.Failed must be inside <Address.Root>.

Props

2 documented props · Native <p> attributes supported

Address.Failed props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { error: GeocoderErrorSlug }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/search-failed.tsx

Address.Retryaction · <button>

Asks the same question again, which is the only useful answer to being throttled.

Required scope

Address.Retry must be inside <Address.Root>.

Props

2 documented props · Native <button> attributes supported

Address.Retry props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/retry.tsx

Address.Attributioncontent · <a>

Always show the active provider's credit, including after its popup closes. It opens in a new tab: following it in this one would leave the form somebody is halfway through.

Props

2 documented props · Native <a> attributes supported

Address.Attribution props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/attribution.tsx

Address.Layoutcontent

Which of the two shapes this screen is, for the part of a layout CSS cannot reach. Width is a stylesheet's job — every size, column count and hit area here is a media query. Words are not: a button that is the width of a phone says "Use my location" and the same button beside a desktop field says "Use my current location", and no breakpoint can rewrite a sentence. Both are written out, and exactly one of them is in the DOM.

Required scope

Address.Layout must be inside <Address.Root>.

Props

3 documented props

Address.Layout props
PropTypeDefault
modeRequired
"wide" | "narrow"—
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/layout.tsx

Address.UseMyLocationaction · <button>

One tap instead of an address. `locating` is handed over because a position takes as long as it takes — ten seconds on a phone that has to wake its radio — and a dimmed button is not an answer to "is it working?". The words change instead. Renders nothing at all where the browser has no geolocation, or the provider cannot reverse a point. A refusal keeps the focused control mounted and disabled, with the explanation in LocationNote. → docs/rules/capability-honesty.md

Capability: reverse

Required scope

Address.UseMyLocation must be inside <Address.Root>.

Props

2 documented props · Native <button> attributes supported

Address.UseMyLocation props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { locating: boolean }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/use-my-location.tsx

Address.LocationNotecontent · <p>

What happened when the browser was asked where it is. Three answers worth different words: a permission denied, which nothing here can undo; a point with nothing mapped at it, which for most of the ocean is the truth; and a lookup that simply failed. The state is handed over rather than flattened.

Capability: reverse

Required scope

Address.LocationNote must be inside <Address.Root>.

Props

2 documented props · Native <p> attributes supported

Address.LocationNote props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { state: Told }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/location-note.tsx

Address.EnterByHandaction · <button>

Opens the fields without choosing anything, for an address no geocoder has.

Required scope

Address.EnterByHand must be inside <Address.Root>.

Props

3 documented props · Native <button> attributes supported

Address.EnterByHand props
PropTypeDefault
inPopup
booleanfalse
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/enter-by-hand.tsx

Address.Entrycontent · <div>

The address is being filled in, field by field. Open as soon as anything has been chosen, because a lookup nobody can see the rest of is a lookup nobody can correct — and 9% of hand-typed addresses have a typo in them. A group rather than a gate around one, because five boxes in a border are five unrelated boxes to somebody hearing them one at a time. Give it a name and a screen reader says what they belong to on the way in.

Required scope

Address.Entry must be inside <Address.Root>.

Props

2 documented props · Native <div> attributes supported

Address.Entry props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/entry.tsx

Address.FieldOrdercontent · <div>

Reorder keyed field groups in the DOM, so reading and tab order agree with the layout.

Required scope

Address.FieldOrder must be inside <Address.Root>.

Props

2 documented props · Native <div> attributes supported

Address.FieldOrder props
PropTypeDefault
childrenRequired
ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/field-order.tsx

Address.FieldGroupcontent · <div>

The rest of the address. Entry is the group of fields; give it an aria-label. EnterByHand opens it with nothing chosen. Field is one text input with its own autofill token and requiredness from the country's metadata; FieldChoice renders a native select where the metadata lists regions, and FieldSuggestions offers countries without preventing others. FieldGroup holds one field and its label, with details to keep it closed until manual entry; FieldOrder sorts its FieldGroup children into the country's order in the DOM. Save, in the card layout, checks the fields in reading order and folds them into the card.

Required scope

Address.FieldGroup must be inside <Address.Root>.

Props

4 documented props · Native <div> attributes supported

Address.FieldGroup props
PropTypeDefault
fieldRequired
AddressFieldName—
details
booleanfalse
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/field-group.tsx

Address.Fieldinput · <input>

One field of the address, other than the street line the box itself holds. Each carries its own autofill token, which is what a browser and a password manager fill on, and a postcode carries a number pad only where postcodes in that country are digits.

Required scope

Address fields must be inside <Address.Root>.

Address.Field must be inside <Address.Root>.

Props

5 documented props · Native <input> attributes supported

Address.Field props
PropTypeDefault
fieldRequired
AddressDetailFieldName—
fallback
booleanfalse
invalidMessage
string""
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/field.tsx

Address.FieldChoiceinput · <select>

Native keyboard and mobile pickers; unrecognised provider values remain editable choices.

Required scope

Address.FieldChoice must be inside <Address.Root>.

Address fields must be inside <Address.Root>.

Props

4 documented props · Native <select> attributes supported

Address.FieldChoice props
PropTypeDefault
fieldRequired
AddressDetailFieldName—
invalidMessage
string""
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/field-choice.tsx

Address.FieldSuggestionscontent · <datalist>

Suggestions keep manual entry possible outside the pinned country subset.

Required scope

Address.FieldSuggestions must be inside <Address.Root>.

Props

3 documented props · Native <datalist> attributes supported

Address.FieldSuggestions props
PropTypeDefault
fieldRequired
AddressDetailFieldName—
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/field-suggestions.tsx

Address.NeedsNumbercontent · <p>

The address is not precise enough to deliver to. "Rue de Rivoli" is a real answer to a real query and a parcel cannot be sent to it — the five Rivolis Photon returns have no house number between them, because the street is what was mapped. Saying so beats letting somebody check out and find out later.

Required scope

Address.NeedsNumber must be inside <Address.Root>.

Props

2 documented props · Native <p> attributes supported

Address.NeedsNumber props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { kind: AddressKind }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/needs-number.tsx

Address.PhoneRootscope

The address's phone number, with its own country list. Its default country is the address's, so a national number is read the way the address writes one, and a new address country moves the default with it. Once somebody picks a country, or types a `+`, the phone keeps that one: a French number goes with a United States address. No phone value goes to the geocoder.

Capability: phone (service, optional)

Required scope

Address.PhoneRoot must be inside <Address.Root>.

Props

6 documented props

Address.PhoneRoot props
PropTypeDefault
enabled

false turns the phone field off. Phone has no service to be missing, so nothing else changes it.

Enabled—
defaultCountry

Where a national number is read when the address has no country yet.

string—
initial

The number the field starts with, as E.164.

string—
allowedCountries

The countries a number may be in, which are also the ones the list offers. Without it, every country.

readonly string[]—
locale
string—
children

Content rendered inside this part.

ReactNode—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/phone-root.tsx

Address.Phonecontent

The number, typed in its country's own format. Typing it is typing in the form, so it ends an undo's offer.

Capability: phone (service, optional)

Required scope

Address.Phone must be inside <Address.Root>.

Props

3 documented props

Address.Phone props
PropTypeDefault
invalidMessage
string—
children

Content rendered inside this part.

ReactNode | ((state: { invalid: boolean; status: PhoneStatus }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/address-phone.tsx

Address.Saveaction · <button>

Collapses the fields to the card, once what is in them would be accepted. Checked here because this is a button and not the form's submit: nothing else would say that a postcode is wrong until somebody checked out. The first field that is empty or invalid takes focus and says why in the browser's own words. → docs/rules/one-submit-per-form.md

Required scope

Address.Save must be inside <Address.Root>.

Props

2 documented props · Native <button> attributes supported

Address.Save props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/save.tsx

Address.FilledMarkcontent · <div>

After a choice or a recent address fills the fields. UndoScope confines Cmd/Ctrl+Z to this address, with no document listener. Undo restores the previous values and focus while its window lasts. FilledMark shows that fields were just filled, as data-state="filled" on their groups.

Required scope

Address.FilledMark must be inside <Address.Root>.

Props

2 documented props · Native <div> attributes supported

Address.FilledMark props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/filled-mark.tsx

Address.Undoaction · <button>

After a choice or a recent address fills the fields. UndoScope confines Cmd/Ctrl+Z to this address, with no document listener. Undo restores the previous values and focus while its window lasts. FilledMark shows that fields were just filled, as data-state="filled" on their groups.

Required scope

Address.Undo must be inside <Address.Root>.

Props

2 documented props · Native <button> attributes supported

Address.Undo props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/undo.tsx

Address.Chosengate

An address has been chosen from the suggestions. In the card layout it waits for the card: while the box and its fields are open the address is being corrected there, and a card beside them would say it twice. For the card of an address nobody chose, typed and saved by hand, see `Address.Settled`.

Required scope

Address.Chosen must be inside <Address.Root>.

Props

1 documented props

Address.Chosen props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { address: Address }) => ReactNode)—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/chosen.tsx

Address.Settledgate

The card layout has an address and is showing it as a card, in place of the box and the fields. Settled by choosing a suggestion or by saving what was typed, so a hand-typed address that no geocoder has gets the same card as a chosen one.

Required scope

Address.Settled must be inside <Address.Root>.

Props

1 documented props

Address.Settled props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { address: Address }) => ReactNode)—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/settled.tsx

Address.Linesscope

The chosen address, one line per line an envelope would have. Built from whichever fields the provider filled, so an address with no street number has one fewer line rather than a blank one — most of the world has no street number. → docs/rules/capability-honesty.md

Required scope

Address.Lines must be inside <Address.Root>.

Props

2 documented props

Address.Lines props
PropTypeDefault
omitStreet
booleanfalse
children

Content rendered inside this part.

ReactNode—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/address-lines.tsx

Address.Linecontent · <span>

Chosen opens once an address is chosen from the list, Settled once the card layout shows its card; both give { address }. Lines repeats once per envelope line and Line renders it; omitStreet leaves out the line the box already shows. Change is the pencil: it forgets the choice and focuses the box, or with edit opens the fields on the address as it stands.

Required scope

Address.Line must be inside <Address.Lines>.

Props

2 documented props · Native <span> attributes supported

Address.Line props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/line.tsx

Address.Changeaction · <button>

Puts the box back to searching, keeping what was typed. With `edit`, opens the fields on the address as it stands instead, which is what a pencil on a card is for when there are fields to correct it in. Over the primitive's own trigger, which moves focus into the box. This button unmounts as it is pressed — the chosen address is what it exists for — and focus would otherwise fall to the body, leaving somebody who pressed "change" with nowhere to type. A card has unmounted the box as well, so the trigger has nothing to focus there: the box comes back with this press, and takes focus once it has.

Required scope

Address.Change must be inside <Address.Root>.

Props

3 documented props · Native <button> attributes supported

Address.Change props
PropTypeDefault
edit
booleanfalse
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/change.tsx

Address.MapRootscope

A small map of the chosen point. MapRoot renders nothing until there is a point and map-tiles is installed. Map is the surface, role="img" with aria-busy while tiles load. MapStatus gets { status }. MapAttribution renders the map's credits that Attribution does not already show, and nothing when there are none.

Capability: map-tiles (service, optional)

Required scope

Address.MapRoot must be inside <Address.Root>.

Props

3 documented props

Address.MapRoot props
PropTypeDefault
config

The map-tiles config, "default" when left out.

string—
enabled

Left out or "optional": the map shows when there is a point, and says it is unavailable when there are no tiles. true: requires map-tiles and throws without it. false: off.

Enabled—
children

Content rendered inside this part.

ReactNode—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/map-root.tsx

Address.Mapcontent · <div>

A small map of the chosen point. MapRoot renders nothing until there is a point and map-tiles is installed. Map is the surface, role="img" with aria-busy while tiles load. MapStatus gets { status }. MapAttribution renders the map's credits that Attribution does not already show, and nothing when there are none.

Capability: map-tiles (service, optional)

Required scope

Address.Map must be inside <Address.MapRoot>.

Props

2 documented props · Native <div> attributes supported

Address.Map props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/map.tsx

Address.MapStatuscontent · <p>

A small map of the chosen point. MapRoot renders nothing until there is a point and map-tiles is installed. Map is the surface, role="img" with aria-busy while tiles load. MapStatus gets { status }. MapAttribution renders the map's credits that Attribution does not already show, and nothing when there are none.

Capability: map-tiles (service, optional)

Required scope

Address.MapStatus must be inside <Address.MapRoot>.

Props

2 documented props · Native <p> attributes supported

Address.MapStatus props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { status: MapPreviewStatus }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/map-status.tsx

Address.MapAttributioncontent · <div>

The map's credits that `Address.Attribution` does not already show, each once. Nothing renders when there are none, so a pattern can put its "Map credits" popover inside without ever showing an empty one.

Capability: map-tiles (service, optional)

Required scope

Address.MapAttribution must be inside <Address.MapRoot>.

Props

2 documented props · Native <div> attributes supported

Address.MapAttribution props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { sources: readonly Source[] }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/map-attribution.tsx

Address.Accuracycontent · <span>

How near the browser thinks it got, in metres. The browser's own number, at 95% confidence, and shown only when it reported one. A browser that says nothing gets no line rather than a plausible-looking estimate, because "accurate to ~40 m" is the difference between the right building and the next one. And only while the address on screen is still the one the browser found: a metre count left over from a position, sitting under an address somebody has since searched for and chosen, is a number about somewhere else. → docs/rules/capability-honesty.md

Capability: reverse

Required scope

Address.Accuracy must be inside <Address.Root>.

Props

2 documented props · Native <span> attributes supported

Address.Accuracy props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { metres: number }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/accuracy.tsx

Address.Valueinput · <input>

What the form sends. The whole address as JSON, because the parts of it that matter most have no field of their own: the coordinate, the ISO country code, and which half of the street line was the house number. Give it a `name` and a `<form>` posts it; read it with `JSON.parse` and it is an `Address`. Empty while every field is, which is how a server tells "nothing entered" from "entered nothing useful".

Required scope

Address.Value must be inside <Address.Root>.

Props

2 documented props · Native <input> attributes supported

Address.Value props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Source: @slices.sh/geocoder/src/headless/value.tsx

When something is missing

No service configuration
Install the geocoder setup below and import "@/services". Required service roots report missing setup; gates do not replace that configuration.
Missing capability or parent scope
Follow each part’s context requirements and the example composition. Capability-aware controls hide when the provider cannot perform their action.
Read the setup guide →