askvity

How to Create a Custom Input in React

Published in React Custom Input Component 6 mins read

Creating a custom input component in React allows you to build reusable form elements with specific styling, behavior, or integrated logic, abstracting the complexity of standard HTML <input> elements.

Why Create a Custom Input Component?

Building custom input components offers several benefits:

  • Reusability: Use the same component across different forms and parts of your application.
  • Consistency: Ensure a uniform look and feel for inputs throughout your UI.
  • Abstraction: Hide complex state management, validation, or formatting logic inside the component.
  • Maintainability: Update the input's behavior or appearance in one place.

Core Steps to Build a Custom Input Component

At its heart, a custom input component in React is typically a functional component that wraps a standard <input> element and manages its state or accepts props to control its behavior and appearance.

Here are the key steps:

  1. Define the Component: Create a new functional component (e.g., CustomTextInput.js).
  2. Manage State (for Controlled Inputs): Use the useState hook to hold the current value of the input. This is common for creating a controlled component where React manages the input's state.
  3. Render the Native <input>: Inside your component, render the standard HTML <input> tag.
  4. Connect State to Input: Pass the state value to the input tag's value prop. This step, as noted in the provided reference, is crucial for making the native input reflect the component's internal state.
  5. Handle Changes: Pass an inline function to its own change (onChange) prop. This inline function (or a separate handler function) receives the change event. Inside this function, you'll update the component's state using the set function provided by useState with the new input value (event.target.value). This step, also highlighted in the reference, is essential for capturing user input and updating the component's state, making the text input fully functional.
  6. Add Props: Accept props to make the component flexible. Common props include type, placeholder, name, id, className, disabled, readOnly, and event handlers like onBlur, onFocus, etc. You can also add custom props for styling or behavior.
  7. Pass Down Props: Spread or explicitly pass down relevant props to the native <input> element.

Example: A Simple Controlled Custom Text Input

import React, { useState } from 'react';
import './CustomTextInput.css'; // Optional: for styling

const CustomTextInput = ({ placeholder, className, ...props }) => {
  // Step 2: Manage State
  const [value, setValue] = useState('');

  // Step 5: Handle Changes
  const handleChange = (event) => {
    setValue(event.target.value);
    // Optional: If the parent component needs to be notified of changes
    if (props.onChange) {
      props.onChange(event);
    }
  };

  return (
    // Optional: Add a wrapper div or label
    <div className="custom-input-wrapper">
      {/* Step 3: Render Native Input */}
      <input
        type="text" // Default type, can be overridden by props
        placeholder={placeholder}
        // Step 4: Connect State to Input
        value={value}
        // Step 5: Handle Changes (using the inline function concept from reference)
        // Using a separate handler function here for clarity
        onChange={handleChange}
        // Step 6 & 7: Add & Pass Down Props
        className={`custom-text-input ${className || ''}`}
        {...props} // Pass down other standard input props (id, name, onBlur, etc.)
      />
      {/* Optional: Add validation messages or other elements */}
    </div>
  );
};

export default CustomTextInput;
  • In the example above, the useState hook manages the input's value.
  • The value prop of the native <input> is bound to this state (value).
  • The onChange event of the native <input> triggers the handleChange function, which updates the state using setValue(event.target.value). This perfectly aligns with the reference's description of passing the value to the input tag and using an inline function to its own change to make it fully functional.
  • Props like placeholder and className are accepted to allow customization from the parent component. The rest of the props (...props) are spread onto the native input for flexibility.

Using Your Custom Component

You can now use this component like any other React component:

import React from 'react';
import CustomTextInput from './CustomTextInput';

function MyForm() {
  // If the parent needs to know the value,
  // you might manage state here too and pass value/onChange props
  // const [username, setUsername] = useState('');

  return (
    <form>
      <label htmlFor="username">Username:</label>
      <CustomTextInput
        id="username"
        name="username"
        placeholder="Enter your username"
        className="form-field"
        // If managing state in parent:
        // value={username}
        // onChange={(e) => setUsername(e.target.value)}
        //
        // If component manages its own state, no need for value/onChange here
      />
      {/* Other form fields */}
    </form>
  );
}

export default MyForm;

Note: The example above shows the custom input managing its own state. For more complex form scenarios where you need to manage multiple inputs' states together in the parent component (e.g., for form submission or validation), you would typically pass the value and onChange props from the parent down to your custom input component, and the custom input would become a "controlled component" that is controlled by its parent.

Customization Options

Custom inputs are powerful because you can add various features:

  • Different Input Types: Accept a type prop and pass it to the native <input>.
  • Labels: Include a <label> element, perhaps linked via an id prop.
  • Icons/Prefixes/Suffixes: Wrap the input and add decorative elements.
  • Validation Display: Show validation error messages or styling based on props.
  • Formatting: Implement logic to format the input value (e.g., currency, phone numbers) as the user types or on blur.
  • Accessibility (a11y): Ensure proper ARIA attributes, keyboard navigation, and focus management.

Key Features Summary

Feature Description Implementation
Value Control Input value is controlled by React state or parent prop. value={stateValue} or value={props.value}
Change Handling Updates state or triggers parent function on user input. onChange={handleChangeFunction}
Props Accepts standard HTML input props and custom ones. {...props} spread operator or explicit prop passing
Rendering Wraps or includes a native <input> element. <input ... />
Custom Logic Can include validation, formatting, event handling beyond basic onChange. Inside component logic

By combining state management (often with useState), rendering the native <input>, binding its value, and handling its onChange event with a function that updates the state, you create a reusable and customizable building block for your forms in React.

Related Articles