Validating React Component Props with prop-types
Tags: javascript, frontenddev, webdev, react
Published: 2019-07-08 17:16:18

---
title: Validating React Component Props with prop-types
published: true
tags: javascript,front-end-developmen,web-development,react
canonical_url: https://blog.logrocket.com/validating-react-component-props-with-prop-types-ef14b29963fc
---

#### Learn how to improve your React components by validating props with prop-types.

![](https://cdn-images-1.medium.com/max/1024/1*OokUL1A5kfzYkQjX5s9rRQ.jpeg)

**Props** are a very important mechanism for passing read-only attributes to React components. These attributes are usually required to be of certain types or forms for them to be used properly in the component.

If a prop is passed to a component in a type or form other than is required, the component may not behave as expected. Hence, a great way of improving React components is **props validation**.

This guide assumes you already have some elementary knowledge of React and is meant for developers who have been using React for any amount of time.

_However, if you are still new to React, you can learn more about React from_ [**_this documentation_**](https://reactjs.org/docs/)_._

Consider this code snippet:

```jsx
import React from 'react';
import ReactDOM from 'react-dom';

function PercentageStat({ label, score = 0, total = Math.max(1, score) }) {
  return (
    <div>
      <h6>{ label }</h6>
      <span>{ Math.round(score / total * 100) }%</span>
    </div>
  )
}

function App() {
  return (
    <div>
      <h1>Male Population</h1>
      <div>
        <PercentageStat label="Class 1" total={360} score={203} />
        <PercentageStat label="Class 2" total={206} />
        <PercentageStat label="Class 3" score={107} />
        <PercentageStat label="Class 4" />
      </div>
    </div>
  )
}

const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
```
In this code snippet, a component named PercentageStat is created, that requires 3 props for proper rendering, namely: label, score and total.

Default values are set for the score and total props in case they are not provided.

Finally, the PercentageStat is rendered 4 times in the App component, each with different props.

The following screenshot shows what the app will look like — _with some Bootstrap styling_:

![](https://cdn-images-1.medium.com/max/1024/0*nB_CEQNguyAvqcrW.png)<figcaption>App with PercentageStat components</figcaption>

Notice, based on usage, that the label prop is expected to be a string. In the same vein, score and total are required to be numeric values because they are used for computing percent. Also notice that total is expected to never be 0 since it is being used as a divisor.

Here is another code snippet showing a modified app that renders PercentageStat components with invalid props.

```jsx
function App() {
  return (
    <div>
      <h1>Male Population</h1>
      <div>
        <PercentageStat label="Class 1" total="0" score={203} />
        <PercentageStat label="Class 2" total={0} />
        <PercentageStat label="Class 3" score={f => f} />
        <PercentageStat label="Class 4" total={{}} score="0" />
      </div>
    </div>
  )
}
```
The following screenshot shows what the app view now looks like:

![](https://cdn-images-1.medium.com/max/1024/0*5CZP-gVxykKir0N6.png)<figcaption>PercentageStat components with invalid props</figcaption>

[![](https://cdn-images-1.medium.com/max/1024/1*fbYhuK2p8bko4WX_Isdueg.png)](https://logrocket.com/signup/)

### Validating props

As demonstrated in the previous section, the reasons for validating component props are very obvious. A couple of techniques can be employed to ensure proper type-checking and validation of your React application.

One very viable option would be to use JavaScript extensions such as [**Flow**](https://flow.org/) or [**TypeScript**](https://www.typescriptlang.org/) to add type-checking to your entire application.

#### propTypes

React provides an internal mechanism for adding type-checking to components. React components use a special property named **propTypes** to setup type-checking.

```jsx
/**
 * FUNCTIONAL COMPONENTS
 */
function ReactComponent(props) {
  // ...implement render logic here
}

ReactComponent.propTypes = {
  // ...prop type definitions here
}


/**
 * CLASS COMPONENTS: METHOD 1
 */
class ReactComponent extends React.Component {
  // ...component class body here
}

ReactComponent.propTypes = {
  // ...prop type definitions here
}


/**
 * CLASS COMPONENTS: METHOD 2
 * Using the `static` class properties syntax
 */
class ReactComponent extends React.Component {
  // ...component class body here
  
  static propTypes = {
    // ...prop type definitions here
  }
}
```
When props are passed to a React component, they are checked against the type definitions configured in the **propTypes** property. When an invalid value is passed for a prop, a warning is displayed on the JavaScript console.

![](https://cdn-images-1.medium.com/max/1024/0*o5XE_YVvwxwrHAyQ.png)<figcaption>Invalid props warning</figcaption>

If default props are set for the React component, the values are first resolved before type-checking against propTypes. Therefore, default values are also subject to the prop type definitions.

Note that, **propTypes** type-checking only happens in development mode, enabling you to catch bugs in your React application while developing. For performance reasons, it is not triggered in production environment.

#### PropTypes

Prior to React **15.5.0** , a utility named **PropTypes** was available as part of the React package, which provided a lot of validators for configuring type definitions for component props. It could be accessed with **React.PropTypes**.

However, in later versions of React, this utility has been moved to a separate package named **prop-types**. So, you need to add it as a dependency for your project in order to get access to the **PropTypes** utility.

```jsx
npm install prop-types --save
```

It can be imported into your project files as follows:

```jsx
import PropTypes from 'prop-types';
```

To learn more about how you can use **prop-types**, how it differs from using **React.PropTypes** and all the available validators, see [**this documentation**](https://github.com/facebook/prop-types/blob/master/README.md).

### Available validators

#### Basic Types

As stated in the previous section, the PropTypes utility exports a lot of validators for configuring type definitions. Here are the validators for the basic data types:

- **`PropTypes.any`**  — the prop can be of any data type
- **`PropTypes.bool`**  — the prop should be a boolean
- **`PropTypes.number`**  — the prop should be a number
- **`PropTypes.string`**  — the prop should be a string
- **`PropTypes.func`**  — the prop should be a function
- **`PropTypes.array`**  — the prop should be an array
- **`PropTypes.object`** — the prop should be an object
- **`PropTypes.symbol`**  — the prop should be a symbol

```jsx
Component.propTypes = {
  anyProp: PropTypes.any,
  booleanProp: PropTypes.bool,
  numberProp: PropTypes.number,
  stringProp: PropTypes.string,
  functionProp: PropTypes.func
}
```
#### Renderable Types

PropTypes also exports the following validators for ensuring that the value passed to a prop can be rendered by React.

- **`PropTypes.node`**  — the prop should be anything that can be rendered by React: number, string, element or an array (or fragment) containing these types
- **`PropTypes.element`**  — the prop should be a React element
```jsx
Component.propTypes = {
  nodeProp: PropTypes.node,
  elementProp: PropTypes.element
}
```

One common usage of the **PropTypes.element** validator is in ensuring that a component has a single child. If the component has no children or multiple children, a warning is displayed on the JavaScript console.

```jsx
Component.propTypes = {
  children: PropTypes.element.isRequired
}
```
#### Instance Types

In cases where you require a prop to be an instance of a particular JavaScript class, you can use the **PropTypes.instanceOf** validator. This leverages the underlying JavaScript **instanceof** operator.

```jsx
Component.propTypes = {
  personProp: PropTypes.instanceOf(Person)
}
```
#### Multiple Types

PropTypes also exports validators that can allow a limited set of values or multiple sets of data types for a prop. Here they are:

- **PropTypes.oneOf**  — the prop is limited to a specified set of values, treating it like an _enum_
- **PropTypes.oneOfType ** — the prop should be one of a specified set of types, behaving like a _union_ of types
```jsx
Component.propTypes = {

  enumProp: PropTypes.oneOf([true, false, 0, 'Unknown']),
  
  unionProp: PropTypes.oneOfType([
    PropType.bool,
    PropType.number,
    PropType.string,
    PropType.instanceOf(Person)
  ])
  
}
```
#### Collection Types

Besides thePropTypes.array and PropTypes.object validators, PropTypes also provides some other validators for more fine-tuned validation of arrays and objects.

Here they are:

**PropTypes.arrayOf** can be used to ensure that the prop is an array in which all items match the specified type.

```jsx
Component.propTypes = {

  peopleArrayProp: PropTypes.arrayOf(
    PropTypes.instanceOf(Person)
  ),
  
  multipleArrayProp: PropTypes.arrayOf(
    PropTypes.oneOfType([
      PropType.number,
      PropType.string
    ])
  )
  
}
```

**PropTypes.objectOf** can be used to ensure that the prop is an object in which all property values match the specified type.

```jsx
Component.propTypes = {

  booleanObjectProp: PropTypes.objectOf(
    PropTypes.bool
  ),
  
  multipleObjectProp: PropTypes.objectOf(
    PropTypes.oneOfType([
      PropType.func,
      PropType.number,
      PropType.string,
      PropType.instanceOf(Person)
    ])
  )
  
}
```
**PropTypes.shape** can be used when a more detailed validation of an object prop is required. It ensures that the prop is an object that contains a set of specified keys with values of the specified types.

```jsx
Component.propTypes = {
  profileProp: PropTypes.shape({
    id: PropTypes.number,
    fullname: PropTypes.string,
    gender: PropTypes.oneOf(['M', 'F']),
    birthdate: PropTypes.instanceOf(Date),
    isAuthor: PropTypes.bool
  })
}
```

For _strict (or exact)_ object matching, you can use **PropTypes.exact** as follows:

```jsx
Component.propTypes = {
  subjectScoreProp: PropTypes.exact({
    subject: PropTypes.oneOf(['Maths', 'Arts', 'Science']),
    score: PropTypes.number
  })
}
```
#### Required Types

The PropTypes validators seen so far all allow the prop to be optional. However, you can chain **isRequired** to any prop validator to ensure that a warning is shown whenever the prop is not provided.

```jsx
Component.propTypes = {

  requiredAnyProp: PropTypes.any.isRequired,
  requiredFunctionProp: PropTypes.func.isRequired,
  requiredSingleElementProp: PropTypes.element.isRequired,
  requiredPersonProp: PropTypes.instanceOf(Person).isRequired,
  requiredEnumProp: PropTypes.oneOf(['Read', 'Write']).isRequired,
  
  requiredShapeObjectProp: PropTypes.shape({
    title: PropTypes.string.isRequired,
    date: PropTypes.instanceOf(Date).isRequired,
    isRecent: PropTypes.bool
  }).isRequired
  
}
```
### Custom validators

Most times, you may need to define some custom validation logic for component props. For example, ensuring that a prop is passed a valid email address. **prop-types** allows you to define custom validation functions that can be used for type-checking props.

#### Basic custom validators

The custom validation function takes three arguments:

1. **`props`**  — An object containing all the props passed to the component

2. **`propName`**  — The name of the prop to be validated

3. **`componentName`**  — The name of the component

It should return an Error object if the validation fails. The error should not be thrown. Also, console.warn should not be used inside the custom validation function.

```jsx

![](htconst isEmail = function(props, propName, componentName) {
  const regex = /^((([^<>()[]\.,;:s@"]+(.[^<>()[]\.,;:s@"]+)*)|(".+"))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,})))?$/;
  
  if (!regex.test(props[propName])) {
    return new Error(`Invalid prop `${propName}` passed to `${componentName}`. Expected a valid email address.`);
  }
}

Component.propTypes = {
  email: isEmail,
  fullname: PropTypes.string,
  date: PropTypes.instanceOf(Date)
}
```
![](https://thepracticaldev.s3.amazonaws.com/i/9ieagimnjojf7vz1x0cz.png)<figcaption>Invalid email prop warning</figcaption>

Custom validation functions can also be used with **PropTypes.oneOfType**. Here is a simple example using the **isEmail** custom validation function in the previous code snippet:

```jsx
Component.propTypes = {
  email: PropTypes.oneOfType([
    isEmail,
    PropTypes.shape({
      address: isEmail
    })
  ])
}
```
Component will be valid in both of these scenarios:

```jsx
<Component email="glad@me.com" />
<Component email={{ address: 'glad@me.com' }} />
```
#### Custom validators and collections

Custom validation functions can also be used with **PropTypes.arrayOf** and **PropTypes.objectOf**. When used this way, the custom validation function will be called for each key in the array or object.

However, the custom validation function will take **_5 arguments instead of 3_**.

1. **`propValue`**  — The array or object itself

2. **`key`**  — The key of the current item in the iteration

3. **`componentName`**  — The name of the component

4. **`location`**  — The location of the validated data. It is usually “prop”

5. **`propFullName`**  — The fully resolved name of the current item being validated. For an array, this will be array[index]. For an object, this will be object.key

Here is a modified version of the **isEmail** custom validation function for use with collection types:

```jsx
const isEmail = function(propValue, key, componentName, location, propFullName) {
  const regex = /^((([^<>()[]\.,;:s@"]+(.[^<>()[]\.,;:s@"]+)*)|(".+"))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,})))?$/;
  
  if (!regex.test(propValue[key])) {
    return new Error(`Invalid prop `${propFullName}` passed to `${componentName}`. Expected a valid email address.`);
  }
}

Component.propTypes = {
  emails: PropTypes.arrayOf(isEmail)
}
```
#### All-purpose custom validators

Taking all that you’ve learned about custom validation functions into account, you can go ahead and create all-purpose custom validators that can be used as standalone validators and also with collection types.

A slight modification to the **isEmail** custom validation function will make it an all-purpose validator as shown in the following code snippet.

```jsx
const isEmail = function(propValue, key, componentName, location, propFullName) {
  // Get the resolved prop name based on the validator usage
  const prop = (location && propFullName) ? propFullName : key;
  
  const regex = /^((([^<>()[]\.,;:s@"]+(.[^<>()[]\.,;:s@"]+)*)|(".+"))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,})))?$/;
  
  if (!regex.test(propValue[key])) {
    return new Error(`Invalid prop `${prop}` passed to `${componentName}`. Expected a valid email address.`);
  }
}

Component.propTypes = {
  email: PropTypes.oneOfType([
    isEmail,
    PropTypes.shape({
      address: isEmail
    })
  ]),
  emails: PropTypes.arrayOf(isEmail)
}
```
### Validating PercentageStat

To wrap up this guide, the following code snippet adds prop types to the **PercentageStat** component that is in the beginning section.

```jsx
import React from 'react';
import PropTypes from 'prop-types';

// The PercentageStat component
function PercentageStat({ label, score = 0, total = Math.max(1, score) }) {
  return (
    <div>
      <h6>{ label }</h6>
      <span>{ Math.round(score / total * 100) }%</span>
    </div>
  )
}

// Checks if a value is numeric
// Either a finite number or a numeric string
function isNumeric(value) {
  const regex = /^(\+|-)?((\d*\.?\d+)|(\d+\.?\d*))$/;
  return Number.isFinite(value) || ((typeof value === "string") && regex.test(value));
}


// Checks if value is non-zero
// Value is first converted to a number
function isNonZero(value) {
  return +value !== 0;
}


// Takes test functions as arguments and returns a custom validation function.
// Each function passed in as argument is expected to take a value argument is
// expected to accept a value and return a boolean if it passes the validation.
// All tests must pass for the custom validator to be marked as passed.
function validatedType(...validators) {
  return function(props, propName, componentName) {
  
    const value = props[propName];
    
    const valid = validators.every(validator => {
      if (typeof validator === "function") {
        const result = validator(value);
        return (typeof result === "boolean") && result;
      }
      
      return false;
    });
    
    if (!valid) {
      return new Error(`Invalid prop \`${propName}\` passed to \`${componentName}\`. Validation failed.`);
    }
    
  }
}

// Set the propTypes for the component
PercentageStat.propTypes = {
  label: PropTypes.string.isRequired,
  score: validatedType(isNumeric),
  total: validatedType(isNumeric, isNonZero)
}
```
### Conclusion

In this guide, we have seen how prop types can be used to improve your React components and ensure that they are used as expected.

If you want to find out more about validating component props in React, you can check [this guide](https://reactjs.org/docs/typechecking-with-proptypes.html).

#### Clap & Follow

If you found this article insightful, feel free to give some rounds of applause if you don’t mind.

You can also follow me on Medium ([Glad Chinda](https://medium.com/u/ddcd0e9719e5)) for more insightful articles you may find helpful. You can also follow me on Twitter ([@gladchinda](https://twitter.com/@gladchinda)).

**_Enjoy coding…_**
* * *
## Plug: [LogRocket](https://logrocket.com/signup/), a DVR for web apps
 
![LogRocket Dashboard Free Trial Banner](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png?resize=1200%2C677&ssl=1)
 
[LogRocket](https://logrocket.com/signup/) is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
 
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
 
[Try it for free](https://logrocket.com/signup/).
* * *
The post [Validating React Component Props with prop-types](https://blog.logrocket.com/validating-react-component-props-with-prop-types-ef14b29963fc/) appeared first on [LogRocket Blog](https://blog.logrocket.com).