AddressBook
Pure presentation of the saved-address list. It never fetches;
the caller passes the addresses it owns and composes each card via
renderItem — wiring the connected actions (AddressDialog,
DeleteAddressButton, SetDefaultAddressButton) itself.
import { AddressBook } from "@evolve-storefront/feature-account/address-book";Renders inside AccountProvider.
Preview
Usage
const { data: book } = useCustomerAddresses();
<AddressBook addresses={book?.items} renderItem={(address) => ( <AddressCard> <AddressLines lines={formatAddressLines(address, { locale })} /> </AddressCard> )}/>;Props
| Prop | Type | Description |
|---|---|---|
addresses? | Address[] | The resolved addresses. The caller owns the query; the view only renders. |
renderItem? | AddressBookItemRenderer<Address> | Renders each address — required for the default composition (no children).
Ignored when children are supplied (pass it to |
empty? | ReactNode | Custom empty state for the default composition. |
emptyAction? | ReactNode | Shown in the default empty state (e.g. an add-address button). |
defaultAddress? | Address | null | Pinned above the rest; see |
searchTerm? | string | The term the caller queries with. Controlled, because the query owns it: the book is paged and searched on the server, so this filters nothing itself. |
onSearchTermChange? | ((searchTerm: string) => void) | Pass to show the search field. |
headingLevel? | HeadingLevel | Level for the group headings. Defaults to 3. |
children? | ReactNode | The composed pieces. Omit for the standard composition, which needs
|
Any other props go to the root element, like on a plain HTML element.
Change the layout
Pass children to AddressBook to arrange its parts yourself. Every part is exported from @evolve-storefront/feature-account/address-book.
AddressBookItemsThe saved addresses in one column, the default first and the rest under letter headings the way a contact list files them.
It renders the page it is handed and owns no pager: which page is showing is the
caller's query state, and a book large enough to need one wants commerce-ui's
AddressBook rather than a longer list.
| Prop | Type | Description |
|---|---|---|
addresses | Address[] | The addresses to render. Kept an explicit prop so |
renderItem | AddressBookItemRenderer<Address> | Renders each address. Required — the feature owns no card markup. |
empty? | ReactNode | Custom empty state. Defaults to |
defaultAddress? | Address | null | The buyer's default delivery address, pinned above the rest under a heading of its own and left out of them. From the customer rather than the page, so it stays on top whichever page of a paged book is showing. |
headingLevel? | HeadingLevel | Level for the group headings. Defaults to 3. |
Any other props go to the root element, like on a plain HTML element.
Loading and empty states
Render these while the data loads or when there is nothing to show, so the page does not jump when it arrives.
| Empty | AddressBookEmpty | Empty state for the address book. |
| Loading | AddressBookSkeleton | Loading state for AddressBook. |
Examples
ComposedThe parts as children: the list and its empty state, composed by the caller.
<AddressBook> <AddressBookItems addresses={book.items} renderItem={renderItem} empty={<AddressBookEmpty>{addAddressButton}</AddressBookEmpty>} /></AddressBook>;Default Pinned With SearchThe full account composition: the default first, under a heading of its own, the rest filed under letters, and a search field above them.
const [searchTerm, setSearchTerm] = useState("");const { data } = useCustomerAddresses({ searchTerm });
<AddressBook addresses={data?.items ?? []} defaultAddress={customer.defaultShippingAddress} searchTerm={searchTerm} onSearchTermChange={setSearchTerm} renderItem={(address) => ( <AddressCard> <AddressCardHeader> <AddressCardTitle>{address.name ?? fullName(address)}</AddressCardTitle> <Button onClick={() => setEditing(address)}>{t("edit")}</Button> </AddressCardHeader> <AddressLines lines={formatAddressLines(address, { locale, includeName: Boolean(address.name) })} /> <AddressCardFooter><DeleteAddressButton address={address} /></AddressCardFooter> </AddressCard> )}/>;EmptyEmpty state with an add-address action.
<AddressBook addresses={book.items} renderItem={renderItem} emptyAction={<Button onClick={() => setAdding(true)}>{t("add-address")}</Button>}/>;LoadingSkeleton and real view adjacent — the only cheap check that the placeholder mirrors the DOM it replaces.
const { data: book, isPending } = useCustomerAddresses();// Same section, grid and card shape as the book, so nothing reflows.if (isPending) return <AddressBookSkeleton />;
