Address and phone
Country, address lookup and phone with dialling code.
Home address and phone
Payroll and your emergency contacts use these details.
address-and-phone.tsx
"use client";
import { useState, type SyntheticEvent } from "react";
import { LuMapPin } from "react-icons/lu";
import {
Alert,
Button,
Combobox,
Input,
InputPhone,
Select,
SelectOption,
type InputPhoneCountry,
} from "@nexera-ui/react";
const COUNTRIES: readonly InputPhoneCountry[] = [
{ code: "GB", name: "United Kingdom", dialCode: "+44" },
{ code: "PT", name: "Portugal", dialCode: "+351" },
{ code: "DK", name: "Denmark", dialCode: "+45" },
{ code: "PK", name: "Pakistan", dialCode: "+92" },
{ code: "AE", name: "United Arab Emirates", dialCode: "+971" },
];
interface Address {
id: string;
line1: string;
city: string;
postcode: string;
}
// Sample lookup results; replace with your address provider's suggestions for the typed text.
const ADDRESSES: Address[] = [
{ id: "a1", line1: "14 Clerkenwell Road", city: "London", postcode: "EC1M 5PA" },
{ id: "a2", line1: "Flat 3, 22 Hackney Road", city: "London", postcode: "E2 7NX" },
{ id: "a3", line1: "8 Deansgate", city: "Manchester", postcode: "M3 1AZ" },
{ id: "a4", line1: "41 Park Street", city: "Bristol", postcode: "BS1 5NH" },
];
/** Address and phone: country, address lookup that fills the fields, and a phone number with its dialling code. */
export default function AddressAndPhone() {
const [country, setCountry] = useState("GB");
const [address, setAddress] = useState({ line1: "", line2: "", city: "", postcode: "" });
const [saved, setSaved] = useState(false);
const set = (key: keyof typeof address) => (value: string) => {
setAddress((a) => ({ ...a, [key]: value }));
};
const onSubmit = (event: SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
setSaved(true); // replace with your update-profile request
};
return (
<div className="@container bg-page px-4 py-8 @3xl:px-8">
<div className="mx-auto grid max-w-2xl gap-6 rounded-xl border border-default bg-surface p-5 shadow-sm @3xl:p-8">
<header className="grid gap-1">
<h2 className="text-heading-h3 text-primary">Home address and phone</h2>
<p className="text-body-default text-secondary">
Payroll and your emergency contacts use these details.
</p>
</header>
{saved ? (
<Alert
tone="success"
title="Contact details saved"
politeness="polite"
onDismiss={() => {
setSaved(false);
}}
/>
) : null}
<form className="grid gap-4" onSubmit={onSubmit}>
<Select
label="Country"
name="country"
autoComplete="country"
value={country}
onChange={(key) => {
setCountry(String(key));
}}
isRequired
>
{COUNTRIES.map((c) => (
<SelectOption key={c.code} id={c.code} label={c.name} />
))}
</Select>
<Combobox
label="Find your address"
placeholder="Start typing a street or postcode"
description="Pick a result to fill in the fields below, or type them yourself."
defaultItems={ADDRESSES}
onChange={(key) => {
const match = ADDRESSES.find((a) => a.id === key);
if (match)
setAddress((a) => ({
...a,
line1: match.line1,
city: match.city,
postcode: match.postcode,
}));
}}
listboxProps={{
emptyTitle: "No matching address",
emptyDescription: "Enter the address yourself below.",
}}
>
{(item: Address) => (
<SelectOption
id={item.id}
label={item.line1}
description={`${item.city} ${item.postcode}`}
leading={<LuMapPin />}
textValue={`${item.line1} ${item.city} ${item.postcode}`}
/>
)}
</Combobox>
<Input
label="Address line 1"
name="address-line1"
autoComplete="address-line1"
value={address.line1}
onChange={set("line1")}
isRequired
errorMessage="Enter the first line of your address."
/>
<Input
label="Address line 2"
name="address-line2"
autoComplete="address-line2"
value={address.line2}
onChange={set("line2")}
description="Optional."
/>
<div className="grid gap-4 @3xl:grid-cols-2">
<Input
label="Town or city"
name="city"
autoComplete="address-level2"
value={address.city}
onChange={set("city")}
isRequired
errorMessage="Enter your town or city."
/>
<Input
label="Postcode"
name="postcode"
autoComplete="postal-code"
value={address.postcode}
onChange={set("postcode")}
isRequired
errorMessage="Enter your postcode."
/>
</div>
<InputPhone
label="Mobile number"
name="phone"
countryFieldName="phone-country"
countries={COUNTRIES}
country={country}
onCountryChange={setCountry}
placeholder="7700 900123"
isRequired
errorMessage="Enter your mobile number."
/>
<div className="flex justify-end">
<Button type="submit" size="md">
Save details
</Button>
</div>
</form>
</div>
</div>
);
}
More forms and data entry blocks
- Contact formName, email, topic and message with validation.
- Add a personCreate a record in a modal.
- Multi-step formLong forms split into steps you can go back to.
- File uploadDrag files in and watch each one upload.
- Date range pickerChoose a start and end date on a calendar.
- Search with suggestionsType ahead and pick from matching results.
- Terms and consentScrollable terms with a required checkbox.
- Choose an optionPick one option from a short list in a dialog.
- Pick a colourBrand or label colour from swatches or a picker.