Address Card + Form

Free

A saved address elegantly displayed — label, default / shipping-billing badges, and edit / remove / set-default actions — plus a companion sv-address-form whose field list comes from the country rather than the template: labels, order and required-ness are all data, so a UK address submits without a county and a Hong Kong one renders no postal code at all. Verification is a six-state enum that never blocks submit, and removing the default address asks where the badge goes next. Cards support a selectable (radio) mode for checkout address pickers.

</>sv-address-card addresscheckoutformecommerceaccounti18ninternational

Also belongs under Forms & Inputs — it is catalogued in Data Display and stays there.

Complexity tier: Interactive The primitive bar, plus declared async states, a keyboard model, focus restoration and undo for destructive actions.

import { SvAddressCardComponent } from '@styloviz/commerce';

Demo & usage

Basic usage

Usage example — open the gallery for the full interactive demo.

An interactive demo for this component lives in the gallery.

Open live demo

More examples

Selectable (checkout picker)

example.htmlAngular
<sv-address-card [address]="a" [selectable]="true" [selected]="a.id === selectedId()" (addressSelected)="selectedId.set(a.id!)" />

Deleting one, and a delete that fails

example.htmlAngular
<sv-address-card [address]="a" [saving]="saving()" [actionError]="error()" (remove)="onRemove($event)" />

Removing the default — choose where the badge goes

example.htmlAngular
<sv-address-card [address]="a" [defaultCandidates]="others(a)" (remove)="onRemove($event)" />

Address form (add / edit)

example.htmlAngular
<sv-address-form [value]="current" (save)="save($event)" (cancelled)="close()" />

Your own countries — a schema is data

example.htmlAngular
<sv-address-form [schemas]="[...DEFAULT_ADDRESS_SCHEMAS, MALTA]" (countryChange)="reverify($event)" />

Advisory verification

example.htmlAngular
<sv-address-form [verification]="{ status: 'unavailable' }" (save)="save($event)" />

A correction offered as a one-press fill

example.htmlAngular
<sv-address-form [verification]="{ status: 'corrected', suggestion: fixed() }" (suggestionApplied)="recheck($event)" />

When to use

  • The account "Addresses" page and the checkout shipping / billing address picker.
  • You want a consistent, premium address display with default and type badges.
  • Pair the card (display) with the form (add / edit) for a complete address book.
  • You ship outside the United States. The form asks for what the country actually has, so nobody has to invent a county or a postal code to get past validation.
  • You verify addresses against a third-party service and need "we could not reach it" to be a different state from "this is wrong".

Async states

None — this component has nothing to load, so it has no loading, empty or error state to drive.

Server writes

Writes
  • remove
  • setDefault

Each payload carries a requestKey — send it with the request so a retry cannot apply the same change twice.

Rollback
None — this component renders a single item out of a collection you own, so there is nothing here to put back. It asks for confirmation first instead, and the item only moves when you change the data.
While saving
Bind saving to stop the action being repeated while the request is out.
On failure
Pass the failure to actionError to show it in place — without taking away what the user was working on.

Inputs

NameTypeDefaultDescription
addressrequiredAddress—The address to display.
selectablebooleanfalseRadio-style selection mode (checkout address picker).
selectedbooleanfalseSelected state (parent-controlled in a radio group).
showActionsbooleantrueShow the action row.
canEditbooleantrueShow the edit action.
canRemovebooleantrueShow the remove action.
canSetDefaultbooleantrueShow the "Set as default" action (hidden when already default).
maskLevelAddressMaskLevel'none'Print the address in full, or with its identifying parts masked — house and flat numbers, the inward half of the postcode and all but the last four phone digits.
confirmRemovebooleantrueAsk before deleting. Defaults to ON, and the previous behaviour was a single click straight through to `remove`. A saved address is not something the component can put back — see AddressActionEvent — and the trash button is a 32px icon sitting next to an edit button of the same size in a grid of near-identical cards. Turn it off only where the host runs its own confirmation dialog.
savingbooleanfalseTrue while a write against this address is being sent. Freezes the actions, so a slow round-trip cannot be turned into two deletes.
actionErrorSvDataError | string | nullnullThe last write failed. Reported on the card, because the card is still here — the host never took it out, and the badge never moved.
defaultCandidatesreadonly Address[][]The other addresses that could take over as default, offered as a choice in the confirmation when THIS address is the default one being removed. Removing the default address used to have no defined transition: the card emitted `remove` and the host was left to guess whether a new default was wanted, which one, and whether the person had any say. The card cannot see the address book, so it cannot pick — but given the candidates it can ask, and the answer rides back on `nextDefaultId`. Left empty, the confirmation says plainly that there will be no default afterwards, which is the outcome the host then has to handle. Ignored entirely when this address is not the default.

Outputs

EventPayload typeDescription
addressSelectedAddressEmitted when the card is chosen in selectable mode. Named `addressSelected`, not `select`: `select` is a native DOM event name (@angular-eslint/no-output-native), so an `(select)` binding is ambiguous with the native one, and `selected` is already taken by the input above. Matches the kit's `<thing>Selected` pattern (see search-bar's `suggestionSelected`).
editAddressEmitted when the edit action is pressed.
removeAddressActionEventThe user confirmed deleting this address. Bind this or nothing happens: the component only asks, it never deletes.
setDefaultAddressActionEvent"Set as default" was pressed. Persist it — the badge follows `address()`.

<sv-address-form>

Also in this family — SvAddressFormComponent from @styloviz/commerce.

Async states

None — this component has nothing to load, so it has no loading, empty or error state to drive.

Inputs

NameTypeDefaultDescription
valueAddress | nullnullInitial value for edit mode; the form resets when it changes.
schemasreadonly AddressSchema[]DEFAULT_ADDRESS_SCHEMASThe countries offered, and the field list each one implies. Replaces the old `countries: string[]`, which could only ever change the names in the dropdown — the fields behind it were fixed, so picking Germany still demanded a state Germany has no field for.
countryLabelstring'Country'Label for the country selector.
titlestring''Optional form heading.
submitLabelstring'Save address'Submit button label.
cancelLabelstring'Cancel'Cancel button label.
showCancelbooleantrueShow the cancel button.
showLabelFieldbooleantrueShow the label field (Home / Work).
showDefaultTogglebooleantrueShow the "Set as default" toggle.
savingbooleanfalseTrue while the host is persisting a submitted address.
verificationAddressVerification | nullnullWhat is known about this address, from the host's verifier. Advisory only. **No status disables submit**, `unavailable` and `failed` included. A verifier is a third party that times out, rate-limits and 500s, and a form that treats a missing answer as a failing one stops accepting good addresses the moment someone else has a bad afternoon.

Outputs

EventPayload typeDescription
saveAddressSaveEventEmitted with the assembled address on a valid submit, alongside the verification status at that moment — so the host can tell "checked and fine" from "never managed to check".
cancelledvoidEmitted when cancel is pressed. Named `cancelled` rather than `cancel`, which is a native DOM event name, and to match `cancelLabel` / `showCancel`.
countryChangestringThe country changed. The field list changed with it, so this is the moment to run a fresh verification rather than re-showing a verdict about the old shape of the address.
suggestionAppliedAddressThe verifier's suggestion was accepted and written into the fields.

Customization & theming

  • Label, default badge and shipping / billing kind badge on the card.
  • Toggle edit / remove / set-default actions individually.
  • Selectable radio mode with a stretched click target and check indicator.
  • `schemas` replaces the old `countries: string[]`: each entry declares its own field list, labels, order, required-ness, autofill token, input mode and — where the subdivisions are a closed set — a dropdown of options. Twelve are built in as `DEFAULT_ADDRESS_SCHEMAS`, chosen to cover every shape rather than to be a world list.
  • Form wording: `countryLabel`, `title`, `submitLabel`, `cancelLabel`, and optional label / default-toggle / cancel.
  • Verification wording is yours: pass `message` for an already-translated sentence, or leave it out for the built-in one per status.

Best practices

  • Do: Use `selectable` cards as a radio group in checkout; keep one `selected` at a time.
  • Do: Bind the form's `value` to edit — it repopulates automatically when the value changes.
  • Do: Handle `save` for `{ address, verification }`; the address carries the original `id` in edit mode, and only the active country's fields are in it.
  • Tip: Hide card actions with `showActions="false"` inside a read-only order summary.
  • Do: Send `event.requestKey` with the delete and ignore a key you have already applied — a retried request must not remove the address that took its place.
  • Do: Bind `[saving]` while the write is out and report the failure through `[actionError]`. The card has no `rollback()` on purpose: the address book is yours, so nothing is applied until your list changes.
  • Don't: Leave `[confirmRemove]` on when the page runs its own confirm dialog — the user is then asked to confirm the same deletion twice.
  • Do: Pass `[defaultCandidates]` on every card, and apply `nextDefaultId` in the SAME request as the delete. An interrupted round-trip otherwise leaves an account with no default address.
  • Don't: Rewrite `isDefault` on every remove. Gate it on `event.wasDefault` — a non-default removal reports no successor, so an unconditional `isDefault: a.id === nextDefaultId` clears the badge off the address that still holds it.
  • Do: Store `event.verification` next to the address. "Verified" and "we never managed to check" are different records, and only one of them is worth re-checking before the next shipment.
  • Don't: Map a verifier timeout onto `failed`. That is what `unavailable` is for — a boolean turns every outage at a third party into lost orders.
  • Don't: Add a country by copying the US schema and renaming the region. Check whether the region is required, whether it exists, and where the postal code sits in the order.

Accessibility

  • Selectable cards expose role="radio" + aria-checked with a full-card click target.
  • The address renders in a semantic <address> element; action buttons have descriptive labels.
  • Form fields have associated labels, aria-invalid on error, and inline required-field messages; visible focus in light and dark mode.
  • Every id is instance-scoped, so a checkout showing a shipping and a billing form together does not point both sets of labels at the first form's inputs.
  • Optional fields say "(optional)" in words. An asterisk on the required ones leaves the reader to guess which convention is in play.
  • The verification strip is `aria-live="polite"`, not an alert: the verdict arrives while the person is still typing, and an assertive region interrupts them mid-field. `verifying` also sets `aria-busy`.
  • The remove confirmation is a `role="group"` with its own label, and it follows the trash button in the DOM so it is the next tab stop from the control that opened it.
  • Removing the default names that fact in the heading, and the successor dropdown has a real `<label>` — the choice is not left to a colour or a badge position.

Feedback on Address Card + Form

Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.

Loads giscus.app and GitHub — nothing is fetched until you click.