City Selector

A ready-made province and city picker for Iran. Built on Combobox, and bundled with all 31 provinces and 1,119 cities — the city field stays disabled until a province is chosen, and both are searchable.

Last updated August 6, 2026

Overview

Examples

Controlled (English)

No city selected.

Controlled (Persian)

شهری انتخاب نشده است.

Locale

By default, labels follow the document's text direction — Persian in RTL, English in LTR. Pass locale to force one regardless of direction — it flips the text direction of the picker too.

locale="fa"

locale="en"

Custom layout

Compose CitySelectorProvince and CitySelectorCity yourself as children of CitySelector for full control over layout, labels, and placeholders.

Form

CitySelector is a plain controlled component — its value / onValueChange pair binds directly into any state or validator, no adapter needed. Here it's validated with Zod alongside a plain text field.

Installation

$ npx shadcn@latest add @persianlabsui/city-selector

This also installs components/ui/combobox.tsx and lib/persian-provinces.ts, the bundled provinces and cities dataset.

Usage

import { CitySelector } from "@/components/ui/city-selector"
 
export function Example() {
  return <CitySelector />
}

Or compose the parts yourself for full control over layout, labels, and placeholders:

import { Label } from "@/components/ui/label"
import {
  CitySelector,
  CitySelectorCity,
  CitySelectorProvince,
} from "@/components/ui/city-selector"
 
export function Example() {
  return (
    <CitySelector locale="en" className="flex-col gap-4 sm:flex-col">
      <div className="flex flex-col gap-1.5">
        <Label>Province</Label>
        <CitySelectorProvince placeholder="Choose a province…" />
      </div>
      <div className="flex flex-col gap-1.5">
        <Label>City</Label>
        <CitySelectorCity placeholder="Choose a city…" />
      </div>
    </CitySelector>
  )
}

API Reference

CitySelector

PropTypeDefaultDescription
valueCitySelectorValueundefinedThe selected province and city. Use when controlled.
defaultValueCitySelectorValue{ province: null, city: null }The initially selected province and city when uncontrolled.
onValueChange(value: CitySelectorValue) => voidCalled when the province or city changes. Selecting a new province resets the city.
locale"fa" | "en"autoForces Persian or English labels, placeholders, and text direction. When omitted, follows the document's text direction (rtl → fa, ltr → en).
disabledbooleanfalseDisables both the province and city comboboxes.
childrenReactNode<CitySelectorProvince /><CitySelectorCity />Pass CitySelectorProvince and CitySelectorCity yourself to fully customize layout, labels, and placeholders.

CitySelectorProvince

PropTypeDefaultDescription
placeholderstringlocale defaultOverrides the province input's placeholder text.
classNamestringundefinedForwarded to the underlying ComboboxInputGroup.

CitySelectorCity

PropTypeDefaultDescription
placeholderstringlocale defaultOverrides the city input's placeholder text.
classNamestringundefinedForwarded to the underlying ComboboxInputGroup.