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
Property | Type | Default | Required | Description |
---|---|---|---|---|
action | ReactNode | - | No | Contents displayed within the ActionLabel. |
countryConfig | CountryConfig | - | No | An array of objects containing the country code and name. The first one will be the default country. |
className | String | - | No | Extend the CSS class names of the component. |
defaultValue | String | - | No | The defaultValue of the input, is only the beginning-state. |
error | Boolean | false | No | Determines whether the component should be visually displayed with an error state. |
id | String | - | Yes | Native HTML id attribute. Also affects label-id and message-id for accessibility reasons. |
label | String | - | No | Contents displayed within the Label above the input. |
labelHidden | Boolean | false | No | Visually the label. (label is still required for a11y) |
message | String | - | No | Contents displayed beneath the label. |
onCountryChange | Function | - | No | The event triggered when the country value changes. |
onBlur | Function | - | No | The event triggered when the PhoneInput gets blurred. This is the best even to use for validation. |
onChange | Function | - | No | The event triggered when the PhoneInput value changes. |
onTextFieldChange | Function | - | No | The event triggered when the input value changes. |
onSelectFocus | Function | - | No | The event triggered when the PhoneInput gets focused. |
optionalLabel | String | - | No | The contents displayed within the OptionalLabel. |
placeholder | String | - | No | A hint to the user of what can be entered in the field. |
success | Boolean | false | No | Determines whether the component should be visually displayed with a success state. |
value | String | - | No | The 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)
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.