Props and PropTypes are important mechanisms for passing read-only attributes between React components.
React props, which stands for “properties,” are used to send data from one component to another. If a component receives the wrong type of props, it can lead to bugs and unexpected errors in your app.
Since JavaScript doesn’t have a built-in type-checking solution, many developers use extensions such as TypeScript and Flow. However, React has an internal mechanism for props validation called PropTypes.
In this comprehensive guide, we’ll show you how to validate props with React PropTypes. We’ll cover the following:
- How React props work
- Why validate props in React?
- Using PropTypes in React
- Using the
prop-types
library - React PropTypes validators
- Custom validators for type-checking React props
- Validating
PercentageStat
in React
If you’re more of a visual learner, check out our video tutorial on React PropTypes:
How React props work
React props allow you to send data — including numbers, strings, functions, objects, arrays, etc. — to a component when you call on that component. If you have multiple components, you can pass data from one component to another.
To pass props between components, you would add them when the component is called, just as you would pass arguments when calling on a regular JavaScript function.
For a deeper dive, check out our beginner’s guide to mastering React props.
Why validate props in React?
When developing a React application, you might encounter the need for a prop to be structured and defined to avoid bugs and errors. Just like a function might have mandatory arguments, a React component might require a prop to be defined, otherwise, it will not render properly. If you forget to pass a required prop into a component that needs it, it could cause your app to behave unexpectedly.
Consider the following code.
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 the above snippet, the component named PercentageStat
requires three props for proper rendering: label
, score
, and total
. Default values are set for the score
and total
props in case they are not provided. PercentageStat
is rendered four times in the App
component, each with different props.
Below is what the app would look like (with some Bootstrap styling):

Notice that, based on usage, 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, total
is expected to never be 0
since it is being used as a divisor.
Below is another code snippet showing a modified app that renders PercentageStat
components with invalid props.
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 app view now looks like this:

Using PropTypes in React
PropTypes is React’s internal mechanism for adding type checking to components.
React components use a special property named propTypes
to set up type checking.
/** * 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.

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 the production environment.
Using the prop-types
library in React
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.
npm install prop-types --save
It can be imported into your project files as follows:
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 the official prop-types
documentation.
React PropTypes validators
The PropTypes utility exports a wide range of validators for configuring type definitions. Below we’ll list the available validators for basic, renderable, instance, multiple, collection, and required prop types.
Basic types
Below are the validators for the basic data types.
PropTypes.any
: The prop can be of any data typePropTypes.bool
: The prop should be a BooleanPropTypes.number
: The prop should be a numberPropTypes.string
: The prop should be a stringPropTypes.func
: The prop should be a functionPropTypes.array
: The prop should be an arrayPropTypes.object
: The prop should be an objectPropTypes.symbol
: The prop should be a symbol
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 — a number, string, element, or array (or fragment) containing these typesPropTypes.element
: The prop should be a React element
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.
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.
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 enumPropTypes.oneOfType
: The prop should be one of a specified set of types, behaving like a union of types
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 validators for more fine-tuned validation of arrays and objects.
PropTypes.arrayOf
PropTypes.arrayOf
ensures that the prop is an array in which all items match the specified type.
Component.propTypes = { peopleArrayProp: PropTypes.arrayOf( PropTypes.instanceOf(Person) ), multipleArrayProp: PropTypes.arrayOf( PropTypes.oneOfType([ PropType.number, PropType.string ]) ) }
PropTypes.objectOf
PropTypes.objectOf
ensures that the prop is an object in which all property values match the specified type.
Component.propTypes = { booleanObjectProp: PropTypes.objectOf( PropTypes.bool ), multipleObjectProp: PropTypes.objectOf( PropTypes.oneOfType([ PropType.func, PropType.number, PropType.string, PropType.instanceOf(Person) ]) ) }
PropTypes.shape
You can use PropTypes.shape
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.
Component.propTypes = { profileProp: PropTypes.shape({ id: PropTypes.number, fullname: PropTypes.string, gender: PropTypes.oneOf(['M', 'F']), birthdate: PropTypes.instanceOf(Date), isAuthor: PropTypes.bool }) }
PropTypes.exact
For strict (or exact) object matching, you can use PropTypes.exact
as follows:
Component.propTypes = { subjectScoreProp: PropTypes.exact({ subject: PropTypes.oneOf(['Maths', 'Arts', 'Science']), score: PropTypes.number }) }
Required types
The PropTypes
validators we’ve explored 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.
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 for type-checking React props
Usually, you need to define some custom validation logic for component props — e.g., 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:
props
, an object containing all the props passed to the componentpropName
, the name of the prop to be validatedcomponentName
, the name of the component
If the validation fails, it should return an Error
object. The error should not be thrown. Also, console.warn
should not be used inside the custom validation function.
const 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) }

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:
Component.propTypes = { email: PropTypes.oneOfType([ isEmail, PropTypes.shape({ address: isEmail }) ]) }
Component
will be valid in both of these scenarios:
<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 are called for each key in the array or object.
However, the custom validation function takes five arguments instead of three:
propValue
, the array or object itselfkey
, the key of the current item in the iterationcomponentName
, the name of the componentlocation
, the location of the validated data (usually“prop”
)propFullName
, the fully resolved name of the current item being validated. For an array, this will bearray[index]
; for an object, it will beobject.key
Below is a modified version of the isEmail
custom validation function for use with collection types.
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 we’ve learned about custom validation functions into account, let’s 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 below.
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
in React
The following code snippet adds prop types to the PercentageStat
component we reviewed at the beginning of this tutorial.
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 // 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) }
Validate React component props in production
Debugging React applications can be difficult, especially when there is complex state. If you’re interested in monitoring and tracking Redux state for all of your users in production, try LogRocket.
LogRocket is like a DVR for web apps, recording literally everything that happens on your site. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.
The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.
Modernize how you debug your React apps — start monitoring for free.
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.
Enjoy coding…
Awesome tutorial, thank you for share this. I believe you covered almost all cases of propTypes usage.
Great article. Only one thing that is needed to fix: in the section “Multiple types” in the unionProp example you wrote PropType instead of PropTypes (found this problem after copying this to my code).
Thanks for pointing this out! The typo is fixed.
Thanks for sharing!
Provided you’re using standard eslint rule set, you should be returning from your custom validator function isEmail at the end of it too, to be consistent with the consistent-return eslint rule (https://eslint.org/docs/rules/consistent-return). It expects that if you use a condition to return from your function when that condition is true, you would also return something (probably different) when condition is false.