react-thaizip

ค้นหาที่อยู่แบบ autocomplete

ค้นหาที่อยู่ไทยจากข้อความที่พิมพ์ พร้อมค่าที่อยู่แบบมีโครงสร้าง

ThaiAddressAutocomplete เหมาะกับหน้าฟอร์มที่ผู้ใช้ต้องการค้นหาที่อยู่ด้วยตำบล อำเภอ/เขต จังหวัด หรือรหัสไปรษณีย์

'use client'

import { ThaiAddressAutocomplete } from '@/components/thai-address-autocomplete'

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

ติดตั้ง

npx react-thaizip add autocomplete

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

วิธีใช้

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

ค่าใน onValueChange คือ ResolvedThaiAddress | null เมื่อผู้ใช้เลือกคำแนะนำจะได้ที่อยู่แบบมีโครงสร้าง และการพิมพ์ให้ข้อความว่างจะล้างที่อยู่ที่เลือกอยู่แล้วด้วยค่า null

ตัวอย่าง

ค้นหาภาษาอังกฤษ

ใช้ locale="en" เพื่อแสดงป้ายกำกับ คำใบ้ และผลลัพธ์เป็นภาษาอังกฤษ ข้อมูลที่ส่งกลับยังมีชื่อทั้งไทยและอังกฤษ

'use client'

import { ThaiAddressAutocomplete } from '@/components/thai-address-autocomplete'

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

ป้ายกำกับ

คอมโพเนนต์ไม่มีป้ายกำกับในตัว ครอบด้วย <label> เพื่อให้ช่องมีชื่อที่ screen reader อ่านได้ และเพิ่มคำอธิบายไว้ด้านล่าง

พิมพ์ตำบล อำเภอ หรือรหัสไปรษณีย์ แล้วเลือกจากรายการ

import { ThaiAddressAutocomplete } from '@/components/thai-address-autocomplete'

export default function AutocompleteLabel() {
  return (
    <div className="flex flex-col gap-2">
      <label className="flex flex-col gap-2 text-sm font-medium">
        ที่อยู่จัดส่ง
        <ThaiAddressAutocomplete />
      </label>
      <p className="text-sm text-muted-foreground">พิมพ์ตำบล อำเภอ หรือรหัสไปรษณีย์ แล้วเลือกจากรายการ</p>
    </div>
  )
}

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

ส่ง value เพื่อควบคุมค่า หรือส่ง defaultValue เพื่อตั้งค่าเริ่มต้นสำหรับโหมด uncontrolled ปุ่มในตัวอย่างนี้ล้างค่าที่ควบคุมอยู่และแสดงผลลัพธ์ที่ callback ส่งกลับมา

ค่าปัจจุบัน

null
'use client'

import { useState } from 'react'
import type { ResolvedThaiAddress } from 'thaizip'
import { ThaiAddressAutocomplete } from '@/components/thai-address-autocomplete'

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

  return (
    <div className="flex flex-col gap-3">
      <ThaiAddressAutocomplete 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 เพื่อปิดช่องค้นหา

'use client'

import { ThaiAddressAutocomplete } from '@/components/thai-address-autocomplete'

export default function AutocompleteDisabled() {
  return <ThaiAddressAutocomplete disabled />
}

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

ส่ง aria-invalid เพื่อแสดงว่าช่องนี้ไม่ผ่านการตรวจสอบ เช่นหลังตรวจฟอร์มไม่ผ่าน

'use client'

import { ThaiAddressAutocomplete } from '@/components/thai-address-autocomplete'

export default function AutocompleteInvalid() {
  return <ThaiAddressAutocomplete aria-invalid />
}

ปรับข้อความ

ใช้ texts เพื่อแทนที่ placeholder และข้อความตอนโหลด/ผิดพลาด/ไม่พบผลลัพธ์ คีย์ที่ไม่ได้ส่งจะใช้ค่าเริ่มต้นตาม locale

import { ThaiAddressAutocomplete } from '@/components/thai-address-autocomplete'

export default function AutocompleteTexts() {
  return (
    <ThaiAddressAutocomplete
      texts={{
        placeholder: 'ค้นหาจากรหัสไปรษณีย์ เช่น 10110',
        emptyText: 'ไม่พบที่อยู่นี้ ลองพิมพ์ชื่ออำเภอแทน',
      }}
    />
  )
}

ปรับสไตล์

แต่ละส่วนของคอมโพเนนต์มี class prop ของตัวเอง (ดู API Reference) class ที่ส่งจะรวมด้วย cn จึงทับค่าเริ่มต้นได้

import { ThaiAddressAutocomplete } from '@/components/thai-address-autocomplete'

export default function AutocompleteStyled() {
  return (
    <ThaiAddressAutocomplete
      inputClassName="rounded-full"
      popupClassName="rounded-2xl"
      itemClassName="rounded-xl"
    />
  )
}

ใช้ในฟอร์ม

ส่ง name เพื่อส่งที่อยู่ที่เลือกไปกับฟอร์มปกติ คอมโพเนนต์จะสร้าง hidden inputs สี่ช่อง (address-subdistrict, address-district, address-province, address-zipcode) และ required จะกันไม่ให้ส่งฟอร์มจนกว่าจะเลือกที่อยู่ ดูรูปแบบอื่นได้ที่ การใช้งานร่วมกับฟอร์ม

FormData ที่ส่ง

null
'use client'

import { useRef, useState, type FormEvent } from 'react'
import { ThaiAddressAutocomplete } from '@/components/thai-address-autocomplete'

export default function FormAutocomplete() {
  const ref = useRef<HTMLInputElement>(null)
  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-3" onSubmit={handleSubmit}>
      <ThaiAddressAutocomplete
        ref={ref}
        name="address"
        required
      />
      <div className="flex gap-2">
        <button type="button" className="rounded-md border border-input bg-background px-3 py-1.5 text-sm hover:bg-accent" onClick={() => ref.current?.focus()}>
          โฟกัสช่องที่อยู่
        </button>
        <button type="submit" className="rounded-md border border-input bg-background px-3 py-1.5 text-sm hover:bg-accent">
          ส่งฟอร์ม
        </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ค่าเริ่มต้นรายละเอียด
valueResolvedThaiAddress | null—ค่าที่ควบคุมอยู่; ส่ง null เพื่อล้าง
defaultValueResolvedThaiAddress | null—ค่าเริ่มต้นของโหมด uncontrolled และเติมข้อความค้นหาเริ่มต้น
onValueChange(address: ResolvedThaiAddress | null) => void—เรียกเมื่อเลือกหรือล้างที่อยู่
namestring—สร้าง hidden inputs สี่ช่อง: <name>-subdistrict, -district, -province, -zipcode
locale'th' | 'en''th'ภาษาของผลลัพธ์และข้อความเริ่มต้น
textsPartial<ThaiAddressAutocompleteTexts>—แทนที่ placeholder, clearAriaLabel, loadingText, errorText, retryLabel, emptyText
indexLoad'mount' | 'visible''mount'โหลดข้อมูลที่อยู่ตอน mount หรือรอจนช่องเลื่อนเข้ามาในจอ
limitnumber10จำนวนคำแนะนำสูงสุด
debouncenumber200ระยะหน่วงก่อนค้นหา (มิลลิวินาที)
thresholdnumber0.4คะแนนความใกล้เคียงขั้นต่ำ (0–1) ที่คำแนะนำจะถูกแสดง
disabledbooleanfalseปิดใช้งานช่องค้นหา
requiredboolean—กำหนดให้ช่องต้องมีค่า
aria-invalidReact.AriaAttributes['aria-invalid']—ระบุสถานะไม่ผ่านการตรวจสอบ
onBlurReact.FocusEventHandler—Vanilla: ทำงานเมื่อ input สูญเสียโฟกัส ส่วน shadcn/ui: ทำงานที่ปุ่ม trigger (HTMLButtonElement)
onError(error: Error) => void—ทำงานเมื่อโหลดดัชนีที่อยู่ไม่สำเร็จ
classNamestring—wrapper หลัก
inputClassNamestring—ช่องพิมพ์ค้นหา
popupClassNamestring—กล่องผลลัพธ์
itemClassNamestring—แต่ละผลลัพธ์
refReact.Ref<HTMLInputElement>—ส่งต่อไปยัง input ใน style shadcn/ui นั้น input อยู่ใน popover จึงเป็น null ระหว่างที่ popover ปิดอยู่

limit, debounce และ threshold ส่งต่อตรงไปยัง hook useThaiAddressAutocomplete ของ thaizip

ดูเพิ่มเติม

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

On this page