Babelize Elements
حقول الإدخال

حقل إدخال الهاتف

حقل إدخال أرقام الهواتف الدولية مع محدّد الدولة وأعلام الدول الرمزية والبحث عن رمز الاتصال. يدعم 50 دولة مع تنسيق وتحقق مدمجين.

التثبيت

npx shadcn@latest add @babelize/phone-input

الاستخدام

"use client";

import { useState } from "react";
import { PhoneInput } from "@/components/ui/phone-input";

export function PhoneField() {
  const [phone, setPhone] = useState("");
  const [countryCode, setCountryCode] = useState("US");

  return (
    <PhoneInput
      value={phone} // omit for uncontrolled
      country={countryCode} // omit for uncontrolled (or use defaultCountry)
      onValueChange={(value, country) => {
        setPhone(value);
        console.log(country.dialCode);
      }}
      onCountryChange={(country) => setCountryCode(country.code)}
      placeholder="Enter phone number"
    />
  );
}

التحكم في الدولة

تتبع الدولة نفس اصطلاح التحكم وعدم التحكم المستخدم للرقم: مرّر country + onCountryChange للتحكم بها، أو defaultCountry لتحديد القيمة الافتراضية غير المتحكَّم بها. عندما يكون country متحكَّمًا به، يكون للمكوّن الأب الكلمة الأخيرة — فاحترم onCountryChange إذا أردت أن يبدّل اكتشاف رمز الاتصال (أدناه) الدولَ.

اكتشاف رمز الاتصال

اكتب أو الصق رقمًا يبدأ بـ + فيبدّل المكوّن الدولة لتطابقه، ويحذف رمز الاتصال والفاصل الذي يليه من الحقل — فالبادئة التي يعلنها + تتقدّم على الدولة المختارة يدويًا:

  • لصق +44 20 7946 0958 يحدّد GB ويترك 20 7946 0958 في الحقل.
  • كتابة + قبل أرقام موجودة أصلًا في الحقل لا تحذفها أبدًا: لا يُستهلك رمز الاتصال إلا إذا أُدخلت أرقامه بعد +. اكتب +1 قبل رقم موجود، فتتبدّل الدولة إلى US بمجرد ظهور 1 — ويحتفظ الرقم بكل أرقامه التي كانت فيه.
  • يفوز أطول رمز اتصال مطابق، لذا يختار +880… بنغلاديش حتى لو تطابق رمز أقصر أيضًا.
  • رموز الاتصال المشتركة تُبقي الدولة المحددة حاليًا إذا كانت إحدى الدول التي تشترك في الرمز المطابق، وإلا تختار الأولى في القائمة المعروضة — فلا يقفز +1 أبدًا بعيدًا عن US أو CA أثناء الكتابة. تنطبق القاعدة نفسها على أي رمز مشترك في قائمة countries مخصصة، مثل +7 إذا عرضت RU وKZ معًا.
  • رمز الاتصال الذي لا يوجد في قائمة countries الخاصة بك يُترك كما هو — فالدولة لا تتبدّل إلا إلى دولة تعرضها فعليًا.
  • بعد التبديل، تعمل قائمة الدول كالمعتاد: اختيار دولة يتجاوز الدولة المكتشفة، ولا يُعاد الاكتشاف حتى المرة التالية التي تبدأ فيها القيمة بـ +.

الخصائص

الخاصيةالنوعمطلوبالوصف
valuestringلارقم الهاتف — مرّره للتحكم في المكوّن
defaultValuestringلارقم الهاتف الأولي عند عدم التحكم
onValueChange(phone: string, country: Country) => voidلادالة استدعاء عند تغيّر رقم الهاتف أو الدولة
countrystringلارمز الدولة المحدد (ISO 3166-1 alpha-2) — مرّره للتحكم في الدولة
onCountryChange(country: Country) => voidلادالة استدعاء عند تغيّر الدولة المحددة — من القائمة أو من اكتشاف رمز الاتصال
defaultCountrystringلارمز الدولة الأولي عند عدم التحكم (ISO 3166-1 alpha-2، مثل "US"، "GB"، "IN"؛ الافتراضي: "US")
countriesCountry[]لاالدول المعروضة، بترتيب العرض (الافتراضي: COUNTRIES)
placeholderstringلاالنص النائب
disabledbooleanلاتعطيل حقل الإدخال
showFlagsbooleanلاإظهار علم الدولة بجانب رمز الاتصال (الافتراضي: true)
size"sm" | "default" | "lg"لاارتفاع الحقل (الافتراضي: "default")
align"start" | "end"لاالحافة التي تصطف القائمة معها في الحقل (الافتراضي: "start")
side"top" | "bottom"لاالجانب المفضل للقائمة؛ يتبدّل عند عدم وجود مساحة (الافتراضي: "bottom")
searchPlaceholderstringلاالنص النائب لبحث الدول (الافتراضي: "Search countries...")
emptyMessageReactNodeلايُعرض عندما لا يطابق البحث أي نتيجة (الافتراضي: "No countries found.")
labelsPartial<PhoneInputLabels>لاتجاوز نصوص الواجهة الإنجليزية المدمجة (انظر أدناه)
displayLocalestringلاالإعدادات المحلية لأسماء الدول، مثل "fr" (الافتراضي: الأسماء الإنجليزية)
maxHeightnumber | stringلاأقصى ارتفاع لقائمة الدول القابلة للتمرير (الافتراضي: "15rem")
labelstringلاتسمية إمكانية الوصول للحقل
classNamestringلاالأصناف الخاصة بالغلاف الجذري
classNamesPhoneInputClassNamesلاأصناف لكل جزء: root، field، trigger، input، content، search، list، item، empty

أي خاصية أخرى — name، required، autoComplete، aria-invalid، data-* — تُمرَّر إلى العنصر الأساسي <input>، ويُعاد توجيه المرجع إليه، فيعمل المكوّن داخل نموذج HTML عادي. ضبط aria-invalid يجعل الحقل كله أحمر، مطابقًا لـ Input في shadcn.

كائن الدولة

الخاصيةالنوعالوصف
codestringرمز ISO 3166-1 alpha-2 (مثل "US"، "GB"، "IN")
dialCodestringرمز الاتصال (مثل "+1"، "+44"، "+91")
namestringاسم الدولة
flagstringعلم الدولة (emoji)

أمثلة

مع Babelize SDK

اقرن حقل إدخال الهاتف مع Babelize SDK للتحقق المراعي للإعدادات المحلية:

"use client";

import { useEffect, useState } from "react";
import { PhoneInput } from "@/components/ui/phone-input";
import { useBabelize } from "@babelize/sdk/react";

export function ContactPhone() {
  const { locale } = useBabelize();
  const [phone, setPhone] = useState("");
  const [countryCode, setCountryCode] = useState("US");

  // The locale picks the country — until the user overrides it through the
  // menu or by pasting a `+` number, which `onCountryChange` must honour.
  useEffect(() => {
    setCountryCode(locale === "en" ? "US" : locale === "de" ? "DE" : "GB");
  }, [locale]);

  return (
    <PhoneInput
      value={phone}
      country={countryCode}
      onCountryChange={(country) => setCountryCode(country.code)}
      onValueChange={(value, country) => {
        setPhone(value);
        // Validate against locale-specific rules
      }}
      placeholder="Enter phone number"
    />
  );
}

مع التحقق من النموذج

"use client";

import { useState } from "react";
import { PhoneInput } from "@/components/ui/phone-input";

export default function CheckoutForm() {
  const [phone, setPhone] = useState("");
  const [error, setError] = useState("");

  const validate = (value: string) => {
    if (value.length < 10) {
      setError("Phone number is too short");
    } else {
      setError("");
    }
  };

  return (
    <div>
      <PhoneInput
        value={phone}
        onValueChange={(value) => {
          setPhone(value);
          validate(value);
        }}
        defaultCountry="US"
        placeholder="Enter phone number"
        aria-invalid={error ? true : undefined}
      />
      {error && <p className="mt-1 text-sm text-destructive">{error}</p>}
    </div>
  );
}

مع فلتر الدول

"use client";

import { COUNTRIES, PhoneInput } from "@/components/ui/phone-input";

// Only the markets you ship to, in the order you want them listed.
const SUPPORTED = ["US", "GB", "CA", "AU"].map((code) =>
  COUNTRIES.find((country) => country.code === code)!,
);

export default function App() {
  return (
    <PhoneInput
      countries={SUPPORTED}
      defaultCountry="US"
      onValueChange={(phone, country) => console.log(phone, country)}
    />
  );
}

تخصيص الأجزاء

يأخذ كل جزء أصنافه الخاصة عبر classNames، وتُدمج بعد القيم الافتراضية:

<PhoneInput
  size="lg"
  align="end"
  classNames={{
    field: "rounded-full",
    trigger: "ps-4",
    content: "w-80",
    item: "py-2",
  }}
/>

نصوص الواجهة المترجمة

مرّر labels لترجمة نص قائمة الدول، وdisplayLocale لعرض أسماء الدول بلغة أخرى. تأتي الأسماء من Intl.DisplayNames في المتصفح، لذا قد تختلف صياغتها قليلًا بين المتصفحات. يطابق البحث الاسم المترجم، بينما يظل onValueChange يُبلغ عن الاسم الإنجليزي للدولة name. تظل الخاصيتان searchPlaceholder وemptyMessage تعملان، وتتغلبان على labels عند ضبطهما معًا.

"use client";

import { PhoneInput } from "@/components/ui/phone-input";

export default function App() {
  return (
    <PhoneInput
      defaultCountry="FR"
      displayLocale="fr"
      label="Numéro de téléphone"
      placeholder="Numéro de téléphone"
      labels={{
        trigger: "Choisir un pays",
        searchPlaceholder: "Rechercher un pays…",
        searchLabel: "Rechercher un pays",
        clearSearch: "Effacer la recherche",
        emptyMessage: "Aucun pays trouvé.",
        listbox: "Choisir un pays",
      }}
    />
  );
}
المفتاحالافتراضييُستخدم في
trigger"Select country"تسمية زر فتح قائمة الدول
searchPlaceholder"Search countries..."النص النائب لحقل البحث
searchLabel"Search countries"تسمية إمكانية الوصول لحقل البحث
clearSearch"Clear search"تسمية إمكانية الوصول لزر المسح
emptyMessage"No countries found."يُعرض عند عدم وجود تطابق
listbox"Select country"تسمية إمكانية الوصول لقائمة الدول

دعم لوحة المفاتيح

تتبع قائمة الدول نمط combobox في WAI-ARIA: يبقى التركيز في حقل البحث، الذي يُعرض كـ role="combobox"، ويُعلَن عن الدولة المميّزة عبر aria-activedescendant.

المفتاحالإجراء
Enter، Space، أو النقرافتح قائمة الدول من زر العلم
ArrowDown / ArrowUp (مغلقة)افتح مع تمييز أول دولة / آخر دولة
ArrowDown / ArrowUpانقل التمييز، مع الالتفاف عند الطرفين
Home / Endمميّز أول دولة / آخر دولة
Enterاختر الدولة المميّزة؛ ينتقل التركيز إلى حقل الرقم
Escapeأغلق القائمة وأعد التركيز إلى زر العلم
الكتابةصفِّ حسب الاسم أو الرمز أو رمز الاتصال؛ يبدأ التمييز من الأعلى مجددًا

يبقى التمييز على الصف الذي ظهر فيه عند فتح القائمة — وتتمرر القائمة أسفله، كالقائمة الأصلية — ولا تتمرر الصفحة نفسها أبدًا. مرّر maxHeight لتغيير ارتفاع قائمة الدول قبل أن تبدأ بالتمرير.

الميزات

  • 50 دولة — محمّلة مسبقًا برموز الاتصال والأعلام والأسماء
  • بحث في القائمة — صفِّ الدول حسب الاسم أو رمز الاتصال
  • أعلام emoji — تُكتشف تلقائيًا من رمز الدولة، مع مفتاح showFlags
  • متاح عبر لوحة المفاتيح — التنقل بمفاتيح الأسهم وHome / End وEnter وEscape
  • تسميات ARIA — حقل البحث role="combobox" مع aria-activedescendant، إضافةً إلى aria-expanded وaria-haspopup وaria-selected
  • قابل للتخصيص بالسمات — منسّق برموز shadcn/ui (border-input، bg-popover، ring-ring)، فيتبع سمتك ووضع الداكن
  • قائمة متحركة — تتلاشى ظهورًا واختفاءً عبر motion، مع احترام إعدادات تقليل الحركة، وتتجه للأعلى عند عدم وجود مساحة أسفلها
  • متحكَّم به / غير متحكَّم به — يعمل مع value وcountry أو بدونهما
  • اكتشاف رمز الاتصال — كتابة +44… أو لصقه يبدّل الدولة إلى GB ويحذف البادئة؛ والرموز المشتركة (+1، +7) تُبقي التحديد الحالي

الدول المدعومة

يأتي الحقل مع 50 دولة محمّلة مسبقًا. استخدم بحث القائمة المنسدلة للعثور على أي دولة بالاسم أو رمز الاتصال. تشمل القائمة الكاملة:

الدولةالرمزرمز الاتصالالعلم
الولايات المتحدةUS+1🇺🇸
المملكة المتحدةGB+44🇬🇧
كنداCA+1🇨🇦
أسترالياAU+61🇦🇺
الهندIN+91🇮🇳
ألمانياDE+49🇩🇪
فرنساFR+33🇫🇷
اليابانJP+81🇯🇵
البرازيلBR+55🇧🇷
كوريا الجنوبيةKR+82🇰🇷
...و40 دولة أخرى عبر بحث القائمة المنسدلة

الاعتماديات

يستخدم هذا المكوّن:

  • clsx وtailwind-merge (مُضمّنة كاعتماديات)
  • lucide-react للأيقونات وmotion لحركة القائمة

الاعتماديات النظيرة:

  • react >= 18
  • react-dom >= 18
  • tailwindcss >= 3

الإسناد

من إنشاء sapatmohit.

في هذه الصفحة