Skip to main content

PhoneField: React

A PhoneField combines a country code selector and a text field, streamlining the input of international phone numbers in forms.

Installation

Before you can start using the @mediahuis/chameleon-react component, you'll need to install it, for more information check: Getting started for developers.

With that done, you're now ready to implement the component in your application.

import { PhoneField } from '@mediahuis/chameleon-react';

export default function Example() {
return <PhoneField label="Example PhoneField" id="id-1" countryConfig={[]} />;
}

Properties

PropertyTypeDefaultRequiredDescription
actionReactNode-NoContents displayed within the ActionLabel.
countryConfigCountryConfig-NoAn array of objects containing the country code and name. The first one will be the default country.
classNameString-NoExtend the CSS class names of the component.
defaultValueString-NoThe defaultValue of the input, is only the beginning-state.
errorBooleanfalseNoDetermines whether the component should be visually displayed with an error state.
idString-YesNative HTML id attribute. Also affects label-id and message-id for accessibility reasons.
labelString-NoContents displayed within the Label above the input.
labelHiddenBooleanfalseNoVisually the label. (label is still required for a11y)
messageString-NoContents displayed beneath the label.
onCountryChangeFunction-NoThe event triggered when the country value changes.
onBlurFunction-NoThe event triggered when the PhoneInput gets blurred. This is the best even to use for validation.
onChangeFunction-NoThe event triggered when the PhoneInput value changes.
onTextFieldChangeFunction-NoThe event triggered when the input value changes.
onSelectFocusFunction-NoThe event triggered when the PhoneInput gets focused.
optionalLabelString-NoThe contents displayed within the OptionalLabel.
placeholderString-NoA hint to the user of what can be entered in the field.
successBooleanfalseNoDetermines whether the component should be visually displayed with a success state.
valueString-NoThe value of the input, only set this if you want to control the component.

Country Config

type Country = {
code: string;
name: string;
};

type CountryGroup = {
label: string;
countries: Country[];
};

type CountryConfig = Country[] | CountryGroup[];

The countryConfig prop is an array of objects that define the countries that are available in the dropdown. It can be an array of an object or an array of array of objects.

For example:

const countryConfig1 = [
{ code: 'BE', name: 'Belgium' },
{ code: 'NL', name: 'Netherlands' },
{ code: 'DE', name: 'Germany' },
];

const countryConfig2 = [
{
label: 'Benelux',
countries: [
{ code: 'BE', name: 'Belgium' },
{ code: 'NL', name: 'Netherlands' },
],
},
{
label: 'Scandinavia',
countries: [
{ code: 'SE', name: 'Sweden' },
{ code: 'NO', name: 'Norway' },
],
},
];

This is to make groups in the dropdown.

Validation

The Chameleon PhoneField does not have any built-in validation. As such, how you handle validation is up to you.

Validation can be done (e.g. by using the onBlur event) using a custom validation function. Below is an example of how you could implement this with the library we recommend: libphonenumber-js. (it also formats the phone-number after validation)

warning

A word of advice: libphonenumber-js is a pretty big library, we advise you to make it as small as possible by using the smallest metadata set possible.

import { PhoneField } from '@mediahuis/chameleon-react';
import { isValidPhoneNumber, parsePhoneNumber } from 'libphonenumber-js';

// Or however you want to use this library
const validatePhoneNumber = (number, countryCode) => {
try {
return isValidPhoneNumber(number, countryCode);
} catch (err) {
error('Validation error:', err);
return false;
}
};

// Functionality to parse numbers to international format
const parsePhone = number => {
try {
return parsePhoneNumber(number).formatInternational();
} catch (err) {
error('Parsing error:', err);
return null;
}
};

export const PhoneNumberComponent = () => {
const [phoneNumber, setPhoneNumber] = useState('');
const [validationResult, setValidationResult] = useState(null);
const [parsedPhoneNumber, setParsedPhoneNumber] = useState(phoneNumber);

const handleOnBlur = (value, countryCode) => {
const isValid = validatePhoneNumber(value, countryCode);
setValidationResult(isValid ? 'valid' : 'invalid');

if (isValid) {
if (!value) {
return;
}

setParsedPhoneNumber(parsePhone(value));
}
};

return (
<PhoneField
countryConfig={countryConfig}
id="phone-1"
label="Phone number"
error={validationResult === 'invalid'}
success={validationResult === 'valid'}
value={parsedPhoneNumber}
onBlur={({ value, inputValue, country }) => {
handleOnBlur(value, country.code);
}}
message={
!!phoneNumber &&
(validationResult === 'invalid'
? `Invalid phone number: ${phoneNumber}`
: `Valid phone number: ${parsedPhoneNumber}`)
}
/>
);
};

required

Chameleon form inputs are required by default, with the required attribute automatically set. To mark a field as optional, pass the optionalLabel prop to remove the required attribute.