nyuchimzizi
Mzizi — an open-architecture project of the Bundu Foundation, operated and developed by Nyuchi. Built on the Five African Minerals palette.
Built by Nyuchi Africav4.0.39
Structured address form with street, city, state, postal code, and country fields with African countries prioritized.
View the full component source code below.
"use client"
import * as React from "react"
import { cn } from "@/lib/utils"
import { Input } from "@/components/ui/input"
interface AddressValue {
street: string
city: string
state: string
postalCode: string
country: string
}
interface AddressInputProps {
value?: Partial<AddressValue>
onChange?: (value: AddressValue) => void
className?: string
}
const AFRICAN_COUNTRIES = [
"Zimbabwe",
"South Africa",
"Kenya",
"Nigeria",
"Ghana",
"Tanzania",
"Uganda",
"Ethiopia",
"Rwanda",
"Mozambique",
"Zambia",
"Botswana",
"Namibia",
"Malawi",
"Senegal",
"Cameroon",
"Egypt",
"Morocco",
] as const
const OTHER_COUNTRIES = [
"United Kingdom",
"United States",
"Canada",
"Australia",
"Germany",
"France",
"India",
"Brazil",
"China",
"Japan",
] as const
const DEFAULT_VALUE: AddressValue = {
street: "",
city: "",
state: "",
postalCode: "",
country: "",
}
function AddressInput({ value, onChange, className }: AddressInputProps) {
const address = { ...DEFAULT_VALUE, ...value }
function update(field: keyof AddressValue, v: string) {
onChange?.({ ...address, [field]: v })
}
return (
<div data-slot="address-input" data-portal="https://design.nyuchi.com/components/address-input" className={cn("flex flex-col gap-3", className)}>
<div className="flex flex-col gap-1.5">
<label className="text-sm font-medium">Street address</label>
<Input
value={address.street}
onChange={(e) => update("street", e.target.value)}
placeholder="123 Main Street"
/>
</div>
<div className="grid grid-cols-2 gap-3">
<div className="flex flex-col gap-1.5">
<label className="text-sm font-medium">City</label>
<Input
value={address.city}
onChange={(e) => update("city", e.target.value)}
placeholder="Harare"
/>
</div>
<div className="flex flex-col gap-1.5">
<label className="text-sm font-medium">State / Province</label>
<Input
value={address.state}
onChange={(e) => update("state", e.target.value)}
placeholder="Harare Province"
/>
</div>
</div>
<div className="grid grid-cols-2 gap-3">
<div className="flex flex-col gap-1.5">
<label className="text-sm font-medium">Postal code</label>
<Input
value={address.postalCode}
onChange={(e) => update("postalCode", e.target.value)}
placeholder="00263"
/>
</div>
<div className="flex flex-col gap-1.5">
<label className="text-sm font-medium">Country</label>
<select
value={address.country}
onChange={(e) => update("country", e.target.value)}
aria-label="Country"
className="h-12 w-full rounded-full border border-input bg-input/30 px-3 text-sm transition-colors outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50"
>
<option value="">Select country</option>
<optgroup label="Africa">
{AFRICAN_COUNTRIES.map((c) => (
<option key={c} value={c}>
{c}
</option>
))}
</optgroup>
<optgroup label="Other">
{OTHER_COUNTRIES.map((c) => (
<option key={c} value={c}>
{c}
</option>
))}
</optgroup>
</select>
</div>
</div>
</div>
)
}
export { AddressInput }
export type { AddressInputProps, AddressValue }
npx shadcn@latest add https://mzizi.dev/api/v1/ui/address-inputFetch this component's metadata and source code from the registry API.
/api/v1/ui/address-inputcomponents/ui/address-input.tsx