---
sidebar_position: 5
---

import PhoneNumber, {
  PhoneNumberDefault,
} from "@site/src/components/phone-number";
import Paper from "@site/src/components/paper";

# PhoneNumber

A Highly customizable phone input component with auto formatting. We are using **react-phone-input-2** package.

<div className="mb-16" />

## Installation

<hr />

1. Install the **react-phone-input-2** package,

<div className="mb-4" />

```bash
npm i react-phone-input-2
```

2. Create a PhoneNumber component, **components/phone-number.tsx**

<div className="mb-4" />

```tsx
import React from "react";
import PhoneInput from "react-phone-input-2";
import type { PhoneInputProps } from "react-phone-input-2";
import "react-phone-input-2/lib/style.css";
import { cn, FieldError, FieldHelperText, FieldClearButton } from "rizzui";

const labelStyles = {
  size: {
    sm: "text-xs mb-1",
    md: "text-sm mb-1.5",
    lg: "text-sm mb-1.5",
    xl: "text-base mb-2",
  },
};

const inputStyles = {
  base: "block peer !w-full focus:outline-none transition duration-200 disabled:!bg-gray-100 disabled:!text-gray-500 disabled:placeholder:!text-gray-400 disabled:!cursor-not-allowed disabled:!border-gray-200",
  error:
    "!border-red hover:enabled:!border-red focus:enabled:!border-red focus:!ring-red",
  size: {
    sm: "py-1 !text-xs !h-8 !leading-[32px]",
    md: "py-2 !text-sm !h-10 !leading-[40px]",
    lg: "py-2 !text-base !h-12 !leading-[48px]",
    xl: "py-2.5 !text-base !h-14 !leading-[56px]",
  },
  rounded: {
    none: "!rounded-none",
    sm: "!rounded-sm",
    md: "!rounded-md",
    lg: "!rounded-lg",
    pill: "!rounded-full",
  },
  variant: {
    flat: "!border-0 focus:ring-2 placeholder:!opacity-90 read-only:focus:!ring-0 !bg-primary-lighter/70 hover:enabled:!bg-primary-lighter/90 focus:!ring-primary/30 !text-primary-dark",
    outline:
      "!bg-transparent focus:ring-[0.6px] !border !border-muted read-only:!border-muted read-only:focus:!ring-0 placeholder:!text-gray-500 hover:!border-primary focus:!border-primary focus:!ring-primary",
    text: "!border-0 focus:ring-2 !bg-transparent hover:!text-primary-dark focus:!ring-primary/30 !text-primary",
  },
};

const buttonStyles = {
  base: "!border-0 !bg-transparent !static [&>.selected-flag]:!absolute [&>.selected-flag]:!top-[1px] [&>.selected-flag]:!bottom-[1px] [&>.selected-flag]:!left-[1px] [&>.selected-flag.open]:!bg-transparent [&>.selected-flag:hover]:!bg-transparent [&>.selected-flag:focus]:!bg-transparent",
  size: {
    sm: "[&>.selected-flag]:!h-[30px]",
    md: "[&>.selected-flag]:!h-[38px]",
    lg: "[&>.selected-flag]:!h-[46px]",
    xl: "[&>.selected-flag]:!h-[54px]",
  },
};

const dropdownStyles = {
  base: "!shadow-xl !text-sm !max-h-[216px] !w-full !my-1.5 !bg-gray-50 [&>.no-entries-message]:!text-center [&>.divider]:!border-muted",
  rounded: {
    none: "!rounded-sm",
    sm: "!rounded",
    md: "!rounded-md",
    lg: "!rounded-lg",
    pill: "!rounded-xl",
  },
  searchBox:
    "!pr-2.5 !bg-gray-50 [&>.search-box]:!w-full [&>.search-box]:!m-0 [&>.search-box]:!px-3 [&>.search-box]:!py-1 [&>.search-box]:!text-sm [&>.search-box]:!capitalize [&>.search-box]:!h-9 [&>.search-box]:!leading-[36px] [&>.search-box]:!rounded-md [&>.search-box]:!bg-transparent [&>.search-box]:!border-muted [&>.search-box:focus]:!border-gray-400/70 [&>.search-box:focus]:!ring-0 [&>.search-box]:placeholder:!text-gray-500",
  highlightListColor:
    "[&>li.country.highlight]:!bg-primary-lighter/70 [&>li.country:hover]:!bg-primary-lighter/70",
};

const clearIconStyles = {
  base: "absolute right-2 group-hover/phone-number:visible group-hover/phone-number:translate-x-0 group-hover/phone-number:opacity-100",
  position: {
    sm: "top-[9px]",
    md: "top-3",
    lg: "top-4",
    xl: "top-5",
  },
};

export interface PhoneNumberProps
  extends Omit<
    PhoneInputProps,
    | "inputClass"
    | "buttonClass"
    | "containerClass"
    | "dropdownClass"
    | "searchClass"
    | "enableSearch"
    | "disableSearchIcon"
  > {
  label?: React.ReactNode;
  error?: string;
  size?: keyof typeof inputStyles.size;
  rounded?: keyof typeof inputStyles.rounded;
  variant?: keyof typeof inputStyles.variant;
  color?: keyof (typeof inputStyles.variant)["active"]["color"];
  clearable?: boolean;
  enableSearch?: boolean;
  onClear?: (event: React.MouseEvent) => void;
  labelClassName?: string;
  inputClassName?: string;
  buttonClassName?: string;
  dropdownClassName?: string;
  searchClassName?: string;
  helperClassName?: string;
  errorClassName?: string;
  helperText?: React.ReactNode;
  className?: string;
}

const PhoneNumber = ({
  size = "md",
  rounded = "md",
  variant = "outline",
  label,
  helperText,
  error,
  clearable,
  onClear,
  enableSearch,
  labelClassName,
  inputClassName,
  buttonClassName,
  dropdownClassName,
  searchClassName,
  helperClassName,
  errorClassName,
  className,
  ...props
}: PhoneNumberProps) => (
  <div className={cn("rizzui-phone-number", className)}>
    {label && (
      <label
        className={cn(
          "block font-medium",
          labelStyles.size[size],
          labelClassName
        )}
      >
        {label}
      </label>
    )}

    <div className="relative group/phone-number">
      <PhoneInput
        inputClass={cn(
          inputStyles.base,
          inputStyles.size[size],
          inputStyles.rounded[rounded],
          inputStyles.variant[variant],
          error && inputStyles.error,
          inputClassName
        )}
        buttonClass={cn(
          buttonStyles.base,
          buttonStyles.size[size],
          // @ts-ignore
          props.inputProps?.disabled && "pointer-events-none",
          // @ts-ignore
          props.inputProps?.readOnly && "pointer-events-none",
          buttonClassName
        )}
        dropdownClass={cn(
          dropdownStyles.base,
          dropdownStyles.rounded[rounded],
          dropdownStyles.highlightListColor,
          dropdownClassName
        )}
        searchClass={cn(dropdownStyles.searchBox, searchClassName)}
        enableSearch={enableSearch}
        disableSearchIcon
        {...props}
      />

      {clearable && (
        <FieldClearButton
          size={size}
          onClick={onClear}
          className={cn(clearIconStyles.base, clearIconStyles.position[size])}
        />
      )}
    </div>

    {!error && helperText && (
      <FieldHelperText size={size} className={helperClassName}>
        {helperText}
      </FieldHelperText>
    )}

    {error && (
      <FieldError size={size} error={error} className={errorClassName} />
    )}
  </div>
);

PhoneNumber.displayName = "PhoneNumber";
export default PhoneNumber;
```

<div className="mb-16" />

## Usage

<hr />

## Default

The default style of **PhoneNumber** component.

<Paper className="block h-96">
  <PhoneNumber
    label="Phone Number"
    country="us"
    preferredCountries={["us"]}
    className="[&_li]:!my-0"
  />
</Paper>

```tsx
import PhoneNumber from "@components/phone-number";

export default function App() {
  return (
    <PhoneNumber
      label="Phone Number"
      country="us"
      preferredCountries={["us"]}
    />
  );
}
```

<div className="mb-16" />

## Variants

You can change the style of **PhoneNumber** with property **variant**.

<Paper className="grid grid-cols-1 sm:grid-cols-2 gap-6">
  <PhoneNumber
    label="Phone Number Active"
    country="us"
    className="[&_li]:!my-0"
  />
  <PhoneNumber
    label="Phone Number Flat"
    country="us"
    variant="flat"
    className="[&_li]:!my-0"
  />
  <PhoneNumber
    label="Phone Number Text"
    country="us"
    variant="text"
    className="[&_li]:!my-0"
  />
</Paper>

```tsx
import PhoneNumber from "@components/phone-number";

export default function App() {
  return (
    <>
      <PhoneNumber label="Phone Number Active" country="us" />
      <PhoneNumber label="Phone Number Flat" country="us" variant="flat" />
      <PhoneNumber
        label="Phone Number Outline"
        country="us"
        variant="outline"
      />
      <PhoneNumber label="Phone Number Text" country="us" variant="text" />
    </>
  );
}
```

<div className="mb-16" />

## Sizes

You can change the style of **PhoneNumber** with property **size**.

<Paper className="gap-6 justify-start items-start">
  <PhoneNumber
    label="Phone Number Small"
    country="us"
    size="sm"
    className="[&_li]:!my-0"
  />
  <PhoneNumber
    label="Phone Number Default"
    country="us"
    className="[&_li]:!my-0"
  />
  <PhoneNumber
    label="Phone Number Large"
    country="us"
    size="lg"
    className="[&_li]:!my-0"
  />
  <PhoneNumber
    label="Phone Number Extra Large"
    country="us"
    size="xl"
    className="[&_li]:!my-0"
  />
</Paper>

```tsx
import PhoneNumber from "@components/phone-number";

export default function App() {
  return (
    <>
      <PhoneNumber label="Phone Number Small" country="us" size="sm" />
      <PhoneNumber label="Phone Number Default" country="us" />
      <PhoneNumber label="Phone Number Large" country="us" size="lg" />
      <PhoneNumber label="Phone Number Extra Large" country="us" size="xl" />
    </>
  );
}
```

<div className="mb-16" />

## Rounded

You can change the style of **PhoneNumber** with property **rounded**.

<Paper className="gap-6 grid grid-cols-1 sm:grid-cols-2 2xl:grid-cols-4">
  <PhoneNumber label="Phone Number" country="us" className="[&_li]:!my-0" />
  <PhoneNumber
    label="Phone Number"
    country="us"
    rounded="lg"
    className="[&_li]:!my-0"
  />
  <PhoneNumber
    label="Phone Number"
    country="us"
    rounded="none"
    className="[&_li]:!my-0"
  />
  <PhoneNumber
    label="Phone Number"
    country="us"
    rounded="pill"
    className="[&_li]:!my-0"
  />
</Paper>

```tsx
import PhoneNumber from "@components/phone-number";

export default function App() {
  return (
    <>
      <PhoneNumber label="Phone Number" country="us" />
      <PhoneNumber label="Phone Number" country="us" rounded="lg" />
      <PhoneNumber label="Phone Number" country="us" rounded="none" />
      <PhoneNumber label="Phone Number" country="us" rounded="pill" />
    </>
  );
}
```

<div className="mb-16" />

## Clearable

You can change the style of **PhoneNumber** with property **clearable**.

<Paper className="block h-96">
  <PhoneNumberDefault />
</Paper>

```tsx
import React from "react";
import PhoneNumber from "@components/phone-number";

export default function App() {
  const [state, setState] = React.useState("");
  return (
    <PhoneNumber
      value={state}
      country="us"
      label="Phone Number"
      preferredCountries={["us"]}
      onChange={(value: string) => setState(value)}
      clearable={!!state}
      onClear={() => {
        setState("");
      }}
    />
  );
}
```

<div className="mb-16" />

## Disabled

You can change the style of **PhoneNumber** with property **disabled**.

<Paper className="block">
  <PhoneNumber
    label="Phone Number"
    country="us"
    disabled
    className="[&_li]:!my-0"
  />
</Paper>

```tsx
import PhoneNumber from "@components/phone-number";

export default function App() {
  return <PhoneNumber label="Phone Number" country="us" disabled />;
}
```

<div className="mb-16" />

## With Helper Text

You can change the style of **PhoneNumber** with property **helperText**.

<Paper className="block h-96">
  <PhoneNumber
    label="Phone Number"
    country="us"
    helperText="This is Helper Text."
    className="[&_li]:!my-0"
  />
</Paper>

```tsx
import PhoneNumber from "@components/phone-number";

export default function App() {
  return (
    <PhoneNumber
      label="Phone Number"
      country="us"
      helperText="This is Helper Text."
    />
  );
}
```

<div className="mb-16" />

## With Error Message

You can show the validation error message using **error** property.

<Paper className="block h-96">
  <PhoneNumber
    label="Phone Number"
    country="us"
    error="This is error message."
  />
</Paper>

```tsx
import PhoneNumber from "@components/phone-number";

export default function App() {
  return (
    <PhoneNumber
      label="Phone Number"
      country="us"
      error="This is error message."
    />
  );
}
```

<div className="mb-20" />

## API Reference

<hr />

<div className="mb-10" />

### PhoneNumber Props

Here is the API documentation of the PhoneNumber component.

|       Props       |                     Type                     |                                 Description                                 |   Default   |
| :---------------: | :------------------------------------------: | :-------------------------------------------------------------------------: | :---------: |
|       label       |                 `ReactNode`                  |                               Set field label                               |    \_\_     |
|       error       |                   `string`                   |                     Show error message using this prop                      |    \_\_     |
|      variant      | [PhoneNumberVariants](#phonenumber-variants) |                     The variants of the components are:                     | `"outline"` |
|       size        |    [PhoneNumberSizes](#phonenumber-sizes)    | The size of the component. `"sm"` is equivalent to the dense input styling. |   `"md"`    |
|      rounded      |  [PhoneNumberRounded](#phonenumber-rounded)  |                          The rounded variants are                           |   `"md"`    |
|     clearable     |                  `boolean`                   |                                                                             |    \_\_     |
|   enableSearch    |                  `boolean`                   |                                                                             |    \_\_     |
|      onClear      |     `(event: React.MouseEvent) => void`      |                                                                             |    \_\_     |
|  labelClassName   |                   `string`                   |    Use labelClassName prop to do some addition style for the field label    |    \_\_     |
|  inputClassName   |                   `string`                   |                   Add custom classes for the input field                    |    \_\_     |
|  buttonClassName  |                   `string`                   |                   Add custom classes for dropdown button                    |    \_\_     |
| dropdownClassName |                   `string`                   |                       Add custom classes for dropdown                       |    \_\_     |
|  searchClassName  |                   `string`                   |                  Add custom classes for dropdown's search                   |    \_\_     |
|  helperClassName  |                   `string`                   |         This prop allows you to customize the helper message style          |    \_\_     |
|  errorClassName   |                   `string`                   |          This prop allows you to customize the error message style          |    \_\_     |
|    helperText     |                 `ReactNode`                  |          Add helper text. It could be string or a React component           |    \_\_     |
|     className     |                   `string`                   | Add custom classes into the component wrapper for extra style like spacing  |    \_\_     |

- You can also use all the other props from [**phone-number-input-2**](https://www.npmjs.com/package/react-phone-input-2) package.

<div className="mb-10" />

### PhoneNumber Variants

```ts
type PhoneNumberVariants = "active" | "flat" | "outline" | "text";
```

<div className="mb-10" />

### PhoneNumber Sizes

```ts
type PhoneNumberSizes = "sm" | "md" | "lg" | "xl";
```

<div className="mb-10" />

### PhoneNumber Rounded

```ts
type PhoneNumberRounded = "sm" | "md" | "lg" | "none" | "pill";
```
