react-thaizip

ฟอร์มที่อยู่แบบเต็ม

กรอกบ้านเลขที่ หมู่ ซอย ถนน พร้อมเลือกที่อยู่ตามลำดับชั้นในฟอร์มเดียว

ThaiAddressForm เหมาะกับฟอร์มที่ต้องการที่อยู่แบบเต็ม คือบ้านเลขที่/หมู่/ซอย/ถนน บวกกับตำบล อำเภอ/เขต และจังหวัด โดยฝัง cascade select ไว้ภายในให้แล้ว

จังหวัด
อำเภอ/เขต
ตำบล/แขวง
รหัสไปรษณีย์
'use client'

import { ThaiAddressForm } from '@/components/thai-address-form'

export default function AddressFormDemo() {
  return <ThaiAddressForm onValueChange={(address) => console.log(address)} />
}

ติดตั้ง

npx react-thaizip add address-form

CLI เลือกไฟล์ให้ตาม style ที่ init บันทึกไว้: โปรเจกต์ที่มี components.json ของ shadcn/ui จะได้ไฟล์ที่ประกอบจาก primitives ของ shadcn (Base UI, Radix หรือ React Aria) นอกนั้นได้แบบ vanilla

วิธีใช้

import { ThaiAddressForm } from '@/components/thai-address-form'
<ThaiAddressForm onValueChange={(address) => console.log(address)} />

ค่าใน onValueChange คือ FullThaiAddress | null จะไม่เป็น null ก็ต่อเมื่อกรอกบ้านเลขที่แล้วและเลือกที่อยู่ตามลำดับชั้นครบทั้งสามระดับ

ตัวอย่าง

กรอกข้อมูลภาษาอังกฤษ

ใช้ locale="en" เพื่อแสดงป้ายกำกับและตัวเลือกเป็นภาษาอังกฤษ ทั้งฟิลด์ข้อความของตัวเองและ cascade select ที่ฝังอยู่

Province
District
Sub-district
Postal code
'use client'

import { ThaiAddressForm } from '@/components/thai-address-form'

export default function AddressFormEn() {
  return <ThaiAddressForm locale="en" onValueChange={(address) => console.log(address)} />
}

ควบคุมค่าจากภายนอก

ส่ง value เพื่อควบคุมค่าทั้งชุด หรือ defaultValue เพื่อตั้งค่าเริ่มต้น การเลือกที่อยู่ตามลำดับชั้นที่ยังเลือกไม่ครบจะไม่ถูกล้าง แม้ value ที่ควบคุมอยู่จะเป็น null

จังหวัด
อำเภอ/เขต
ตำบล/แขวง
รหัสไปรษณีย์

ค่าปัจจุบัน

null
'use client'

import { useState } from 'react'
import { ThaiAddressForm, type FullThaiAddress } from '@/components/thai-address-form'

export default function AddressFormControlled() {
  const [address, setAddress] = useState<FullThaiAddress | null>(null)

  return (
    <div className="flex flex-col gap-3">
      <ThaiAddressForm value={address} onValueChange={setAddress} />
      <div>
        <button type="button" className="rounded-md border border-input bg-background px-3 py-1.5 text-sm hover:bg-accent" onClick={() => setAddress(null)}>
          ล้างค่า
        </button>
      </div>
      <p className="text-sm font-medium">ค่าปัจจุบัน</p>
      <pre className="max-h-72 overflow-auto rounded-md border bg-muted p-3 text-xs">{JSON.stringify(address, null, 2)}</pre>
    </div>
  )
}

ปิดใช้งาน

ส่ง disabled เพื่อปิดทุกช่องกรอกและทุก select

จังหวัด
อำเภอ/เขต
ตำบล/แขวง
รหัสไปรษณีย์
'use client'

import { ThaiAddressForm } from '@/components/thai-address-form'

export default function AddressFormDisabled() {
  return <ThaiAddressForm disabled />
}

ไม่ผ่านการตรวจสอบ

ส่ง aria-invalid เพื่อทำเครื่องหมายว่าช่องกรอกทั้งสี่และ trigger ของ cascade ไม่ผ่านการตรวจสอบ

จังหวัด
อำเภอ/เขต
ตำบล/แขวง
รหัสไปรษณีย์
'use client'

import { ThaiAddressForm } from '@/components/thai-address-form'

export default function AddressFormInvalid() {
  return <ThaiAddressForm aria-invalid />
}

ปรับข้อความ

ใช้ texts สำหรับป้ายกำกับและ placeholder ของคอมโพเนนต์นี้ และ cascadeTexts สำหรับ cascade select ที่ฝังอยู่

จังหวัด
อำเภอ/เขต
ตำบล/แขวง
รหัสไปรษณีย์
import { ThaiAddressForm } from '@/components/thai-address-form'

export default function AddressFormTexts() {
  return (
    <ThaiAddressForm
      texts={{
        houseNoLabel: 'บ้านเลขที่ / ห้อง',
        houseNoPlaceholder: 'เช่น 99/9 ห้อง 1203',
        streetLabel: 'อาคาร / ถนน',
      }}
    />
  )
}

ใช้ในฟอร์ม

ฟอร์มแบบหน้าชำระเงิน: มีช่องชื่อผู้รับและเบอร์โทรคู่กับที่อยู่ พร้อมปุ่มยกเลิกและบันทึก การส่ง name จะสร้าง hidden inputs แปดช่อง FormData ธรรมดาจึงได้ที่อยู่ครบทั้งชุด ดูรูปแบบอื่นได้ที่ การใช้งานร่วมกับฟอร์ม

จังหวัด
อำเภอ/เขต
ตำบล/แขวง
รหัสไปรษณีย์

FormData ที่ส่ง

null
'use client'

import { useState, type FormEvent } from 'react'
import { ThaiAddressForm } from '@/components/thai-address-form'

export default function AddressFormSubmit() {
  const [payload, setPayload] = useState<Record<string, FormDataEntryValue> | null>(null)

  function handleSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault()
    setPayload(Object.fromEntries(new FormData(event.currentTarget)))
  }

  return (
    <form className="flex flex-col gap-4" onSubmit={handleSubmit} onReset={() => setPayload(null)}>
      <div className="grid gap-4 sm:grid-cols-2">
        <label className="flex flex-col gap-1.5 text-sm font-medium">
          ชื่อผู้รับ
          <input name="recipient" required className="h-9 rounded-md border border-input bg-background px-3 text-sm" />
        </label>
        <label className="flex flex-col gap-1.5 text-sm font-medium">
          เบอร์โทรศัพท์
          <input name="phone" type="tel" required className="h-9 rounded-md border border-input bg-background px-3 text-sm" />
        </label>
      </div>
      <ThaiAddressForm name="address" required />
      <div className="flex justify-end gap-2">
        <button type="reset" className="rounded-md border border-input bg-background px-3 py-1.5 text-sm hover:bg-accent">
          ยกเลิก
        </button>
        <button type="submit" className="rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90">
          บันทึกที่อยู่
        </button>
      </div>
      <p className="text-sm font-medium">FormData ที่ส่ง</p>
      <pre className="max-h-72 overflow-auto rounded-md border bg-muted p-3 text-xs">{JSON.stringify(payload, null, 2)}</pre>
    </form>
  )
}

API Reference

PropTypeค่าเริ่มต้นรายละเอียด
valueFullThaiAddress | null—ค่าที่ควบคุมอยู่; ส่ง null เพื่อล้าง
defaultValueFullThaiAddress | null—ค่าเริ่มต้นของโหมด uncontrolled เติมทั้งช่องข้อความและ cascade ที่ฝังอยู่
onValueChange(address: FullThaiAddress | null) => void—เรียกเมื่อบ้านเลขที่ไม่ว่างและเลือกครบทั้งสามระดับ หรือเมื่อค่ากลับมาไม่ครบอีกครั้ง
namestring—สร้าง hidden inputs 8 ช่อง: 4 ช่องของ cascade (-subdistrict/-district/-province/-zipcode) และ 4 ช่องของคอมโพเนนต์นี้ (-houseno/-moo/-soi/-street)
locale'th' | 'en''th'ภาษาของข้อความและป้ายกำกับ ทั้งของคอมโพเนนต์นี้และ cascade ที่ฝังอยู่
textsPartial<ThaiAddressFormTexts>—แทนที่ป้ายกำกับและ placeholder ของบ้านเลขที่/หมู่/ซอย/ถนน
cascadeTextsPartial<ThaiAddressCascadeSelectTexts>—ส่งต่อเป็น texts ของ cascade select ที่ฝังอยู่
indexLoad'mount' | 'visible''mount'ส่งต่อไปยังตัวโหลดดัชนีที่อยู่ของ cascade ที่ฝังอยู่
disabledbooleanfalseปิดใช้งานทุกช่องข้อความและ cascade ที่ฝังอยู่
requiredbooleanfalseกำหนดให้ช่องบ้านเลขที่และ cascade ต้องมีค่า (หมู่/ซอย/ถนนยังไม่บังคับ)
aria-invalidReact.AriaAttributes['aria-invalid']—ทำเครื่องหมายว่าช่องข้อความทั้งสี่และ trigger ของ cascade ไม่ผ่านการตรวจสอบ
onBlurReact.FocusEventHandler<HTMLInputElement>—ทำงานเฉพาะเมื่อช่องบ้านเลขที่สูญเสียโฟกัส
onError(error: Error) => void—ทำงานเมื่อโหลดดัชนีที่อยู่ไม่สำเร็จ (จัดการโดย cascade ที่ฝังอยู่)
classNamestring—wrapper หลัก
labelClassNamestring—ป้ายกำกับของช่องข้อความและ cascade
inputClassNamestring—ช่องบ้านเลขที่/หมู่/ซอย/ถนน
triggerClassNamestring—trigger ของ select และช่องรหัสไปรษณีย์ใน cascade
popupClassNamestring—กล่องตัวเลือกของ cascade
itemClassNamestring—แต่ละตัวเลือกของ cascade
refReact.Ref<HTMLInputElement>—ส่งต่อไปยังช่องบ้านเลขที่

ดูเพิ่มเติม

ดู การใช้งานร่วมกับฟอร์ม สำหรับการส่งค่าที่อยู่ และ การปรับแต่ง สำหรับปรับหน้าตา ส่วนคอมโพเนนต์ที่ฝังอยู่ ดู cascade select

On this page