Pattern · Navigation Bars

New

Location Header SwiftUI Block

The header of a delivery or local app: the address and its chooser, search, a Now or Schedule pill, and the bag with its count.

Deliver to over the current address opens a chooser of saved addresses with a radio selection, Use current location through CoreLocation and Add address. Picking an address runs your check in the row before it applies. A search field, a Now or Schedule pill and the bag with its count complete the header.

  • SwiftUI
  • iOS 17.0+
  • location-header
Get SwiftPieces Pro

$199 once, every piece included. See how installing works · Sign in

01

What's included

SwiftUI source you own, built on Apple frameworks only.

  • The current address with a chooser of saved addresses and a radio selection
  • Use current location asks for permission, finds you and handles location being off
  • Your address check runs in the row, with its error shown in place
  • A pill for Now or a scheduled time, with a menu to switch
  • A search field and the bag's count, with grey shapes while loading

02

Implementation notes

How it behaves, what it handles, and the decisions behind it.

"Deliver to" sits over the current address, its name in semibold and the street after it, with a chevron that opens the address chooser; the bag sits beside it with its item count in the accent. Under them a search field opens your search, and a pill reads Now or the time you scheduled, with a menu to switch back to now or open your scheduler. The chooser is a sheet: saved addresses with a radio selection, Use current location and Add address. Picking an address runs your check in the row with a spinner, moves the radio, updates the header and closes the sheet; a thrown error stays in the row in the danger colour and keeps the old address. Use current location asks for When In Use permission the first time, finds you once and hands the coordinate to your closure for an address; when location is off it says so with Open Settings. Pass nil addresses while they load and the header shows grey shapes in its own layout.

Notes

  • LocationHeader(addresses:selection:timing:cartCount:searchPrompt:onSelect:onUseCurrentLocation:onAddAddress:onSchedule:onSearch:onCart:) takes the saved addresses, a binding to the chosen Address (nil reads "Choose an address") and a binding to the Timing. It is a section with no background, padding or scroll view; the chooser owns its sheet and the scroll view inside it.
  • LocationHeader.Address has an id, a label ("Home"), one line of the address and an SF Symbol for its row. Address.samples holds Home, Work and Sam's.
  • LocationHeader.Timing holds the estimate for an order now ("25–35 min") and an optional scheduled date. The pill reads "Now", a time today, or the weekday and time.
  • onSelect is async throws and runs before an address becomes the selection, so you can check that you deliver there. Throw a LocalizedError ("We don't deliver there yet") to show its message in the row, or CancellationError() to back out quietly. Without it a pick applies at once.
  • onUseCurrentLocation receives a CLLocationCoordinate2D and returns an Address, from CLGeocoder or your own places service; the result becomes the selection. The row shows "Waiting for permission", "Finding you…", "Location access is off for this app." with Open Settings, or the error. Nil hides the row.
  • onAddAddress opens your new address form after the sheet closes; onSchedule opens your scheduler from the pill's menu and nil leaves the pill a plain label; onSearch and onCart nil hide the field and the bag.
  • Haptics mark a pick with a selection tick and a failure with an error.
  • VoiceOver reads the address as one button ("Deliver to, Home, 221 Elm Street, Apt 4"), the bag as "Bag, 2 items", the pill as "Delivery time, Now", and each saved address with Selected on the current one. It announces the new address, a denied permission and failures. Rows grow with Dynamic Type and every control has a 44 point target.
  • Reduce Motion turns the loading shimmer off and state changes into short fades.
  • LocationHeaderExample at the end of LocationHeader.swift is the Order tab in the preview: delivering Home with two items in the bag, an address check that takes a moment, and Use current location through CLGeocoder. Pass wrapsInNavigationStack: false to push it in your own stack.

Theming

  • Reads SPTheme from @Environment(\.spTheme) and requires the design-system item.
  • "Deliver to" is type.footnote in textSecondary; the address is type.body, its label semibold textPrimary and its line textSecondary.
  • The search field and the pill sit on fill with a 1 point separator stroke, the field at radius.md and the pill as a capsule; the prompt is textTertiary, the pill's time type.subhead medium in textPrimary with monospaced digits.
  • The bag is fill with a separator ring; its count is the accent with accentOn figures, ringed in bg: the block's only accent.
  • The chooser sits on bg, its cards on surface with radius.lg and SPHairline dividers inset to the text. Symbols are textSecondary. The radio is a separator ring, or a textPrimary disc with a check in surface when chosen. Failures are danger.
  • Changes use motion.smooth and motion.snappy, adapted for Reduce Motion.

Requirements

  • NSLocationWhenInUseUsageDescription in Info.plist for Use current location. Leave out onUseCurrentLocation and it needs nothing.