"use client";
import { Controller, useForm } from "react-hook-form";
import { isValidPhoneNumber } from "react-phone-number-input";
import { zodResolver } from "@hookform/resolvers/zod";
import { styled } from "styled-system/jsx";
import { z } from "zod";
import { toast } from "@/hooks/use-toast";
import { Button } from "@/components/ui/button";
import { Field, FieldDescription, FieldError, FieldLabel } from "@/components/ui/field";
import { PhoneInput } from "@/components/ui/phone-input";
const formSchema = z.object({
phone: z.string().refine(isValidPhoneNumber, { message: "Invalid phone number" }),
});
export default function PhoneInputDemo() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
phone: "",
},
});
const onSubmit = form.handleSubmit((data) => {
toast({
title: "You submitted the following values:",
description: (
<styled.pre
css={{ mt: "2", w: "340px", rounded: "md", bg: "slate.950", p: "4", borderWidth: "1px" }}
>
<styled.code css={{ color: "white" }}>{JSON.stringify(data, null, 2)}</styled.code>
</styled.pre>
),
});
});
return (
<styled.form
onSubmit={onSubmit}
css={{ display: "flex", flexDir: "column", alignItems: "flex-start", spaceY: "8" }}
>
<Controller
control={form.control}
name="phone"
render={({ field, fieldState }) => (
<Field
data-invalid={fieldState.invalid}
css={{ display: "flex", flexDir: "column", alignItems: "flex-start" }}
>
<FieldLabel css={{ textAlign: "left" }}>Phone Number</FieldLabel>
<PhoneInput placeholder="Enter a phone number" {...field} />
<FieldDescription css={{ textAlign: "left" }}>Enter a phone number</FieldDescription>
<FieldError>{fieldState.error?.message}</FieldError>
</Field>
)}
/>
<pre>
<styled.code css={{ color: "muted.fg" }}>
{JSON.stringify(form.watch("phone"), null, 2)}
</styled.code>
</pre>
<Button type="submit">Submit</Button>
</styled.form>
);
}
About
The Phone Input component is built on top of React Phone Number Input.
Thanks to omeralpi for implementing this component.
Installation
npx nore-ui-cli@latest add phone-inputUsage
import { PhoneInput } from "@/components/ui/phone-input";
const [value, setValue] = React.useState("");
return <InputPhone value={value} onChange={setValue} />;
Examples
Setting default country
"use client";
import { useState } from "react";
import { PhoneInput } from "@/components/ui/phone-input";
export default function PhoneInputDefaultCountry() {
const [phoneNumber, setPhoneNumber] = useState("");
return (
<PhoneInput
value={phoneNumber}
onChange={setPhoneNumber}
defaultCountry="ID"
placeholder="Enter a phone number"
/>
);
}
Internationalization
"use client";
import { useState } from "react";
import ja from "react-phone-number-input/locale/ja";
import { PhoneInput } from "@/components/ui/phone-input";
export default function PhoneInputInternationalization() {
const [phoneNumber, setPhoneNumber] = useState("");
return (
<PhoneInput
value={phoneNumber}
onChange={setPhoneNumber}
labels={ja}
placeholder="電話番号を入力してください"
/>
);
}
Force international format
"use client";
import { useState } from "react";
import { PhoneInput } from "@/components/ui/phone-input";
export default function PhoneInputInternational() {
const [phoneNumber, setPhoneNumber] = useState("");
return (
<PhoneInput value={phoneNumber} onChange={setPhoneNumber} international defaultCountry="ID" />
);
}
Force national format
"use client";
import { useState } from "react";
import { PhoneInput } from "@/components/ui/phone-input";
export default function PhoneInputNational() {
const [phoneNumber, setPhoneNumber] = useState("");
return (
<PhoneInput
value={phoneNumber}
onChange={setPhoneNumber}
international={false}
defaultCountry="ID"
placeholder="Enter a phone number"
/>
);
}
initialValueFormat
"use client";
import { useState } from "react";
import { PhoneInput } from "@/components/ui/phone-input";
export default function PhoneInputInitial() {
const [phoneNumber, setPhoneNumber] = useState("");
return (
<PhoneInput
value={phoneNumber}
onChange={setPhoneNumber}
initialValueFormat="national"
placeholder="Enter a phone number"
/>
);
}
Formatting value
National:
International:
Country code:
"use client";
import { useState } from "react";
import {
Country,
formatPhoneNumber,
formatPhoneNumberIntl,
getCountryCallingCode,
} from "react-phone-number-input";
import { styled } from "styled-system/jsx";
import { PhoneInput } from "@/components/ui/phone-input";
export default function PhoneInputFormattingValue() {
const [country, setCountry] = useState<Country>();
const [phoneNumber, setPhoneNumber] = useState("");
return (
<div>
<PhoneInput
value={phoneNumber}
onChange={setPhoneNumber}
onCountryChange={setCountry}
placeholder="Enter a phone number"
/>
<styled.div css={{ mt: "4", spaceY: "2", textStyle: "sm" }}>
<div>National: {phoneNumber && formatPhoneNumber(phoneNumber)}</div>
<div>International: {phoneNumber && formatPhoneNumberIntl(phoneNumber)}</div>
<div>Country code: {country && getCountryCallingCode(country)}</div>
</styled.div>
</div>
);
}