Building a Labeled Input Component in React with TypeScript
This challenge focuses on creating a reusable React component that renders an input field alongside a descriptive label. This is a fundamental building block for any form and demonstrates understanding of component composition, props, and TypeScript typing. Successfully completing this challenge will solidify your ability to create modular and type-safe React components.
Problem Description
You are tasked with creating a LabeledInput component in React using TypeScript. This component should accept a label text, an input type (e.g., "text", "number", "email"), and a value as props. The component should render an HTML <label> element associated with an HTML <input> element. The label's for attribute should correspond to the input's id attribute, ensuring proper accessibility. The input's value attribute should be dynamically set based on the value prop. The component should also accept an onChange prop, which is a function that will be called when the input's value changes.
Key Requirements:
- Label and Input Association: The label must be correctly associated with the input using the
forandidattributes. - Dynamic Value: The input's
valueattribute must be controlled by thevalueprop. - Change Handling: The component must correctly call the
onChangeprop when the input value changes. - Input Type: The input's
typeattribute must be set based on thetypeprop. - TypeScript Typing: The component must be written in TypeScript with appropriate type definitions for props.
Expected Behavior:
When the component is rendered, it should display a label above an input field. The input field should initially have the value specified by the value prop. As the user types into the input field, the onChange prop function should be called with the new input value.
Edge Cases to Consider:
- Empty label text: Handle the case where the
labelprop is an empty string gracefully (e.g., by not rendering the label). - Invalid input type: While not strictly required, consider how you might handle an invalid
typeprop (e.g., by logging a warning or using a default type).
Examples
Example 1:
Input: <LabeledInput label="Name" type="text" value="John Doe" onChange={(e) => console.log(e.target.value)} />
Output:
<label for="name-input">Name</label>
<input type="text" id="name-input" value="John Doe" onChange={(e) => console.log(e.target.value)}/>
Explanation: A label "Name" is associated with a text input field initialized with the value "John Doe". The onChange handler logs the input value to the console.
Example 2:
Input: <LabeledInput label="Age" type="number" value="25" onChange={(e) => console.log(e.target.value)} />
Output:
<label for="age-input">Age</label>
<input type="number" id="age-input" value="25" onChange={(e) => console.log(e.target.value)}/>
Explanation: A label "Age" is associated with a number input field initialized with the value "25". The onChange handler logs the input value to the console.
Example 3: (Edge Case)
Input: <LabeledInput label="" type="email" value="test@example.com" onChange={(e) => console.log(e.target.value)} />
Output:
<input type="email" id="email-input" value="test@example.com" onChange={(e) => console.log(e.target.value)}/>
Explanation: Because the label is empty, the label element is not rendered. The email input field is initialized with the value "test@example.com".
Constraints
- The component must be written in functional component style using React Hooks (if needed).
- The component must be written in TypeScript.
- The
idattribute for the input field should be dynamically generated based on thelabelprop (e.g.,label.toLowerCase().replace(/ /g, '-') + '-input'). - The component should be reusable and accept different input types and values.
Notes
- Consider using a unique identifier for the input field's
idto avoid conflicts if you use multipleLabeledInputcomponents on the same page. - Think about how you might handle optional props like
placeholderorrequired. While not required for this challenge, it's good practice to consider extensibility. - Focus on creating a clean, readable, and well-typed component. Accessibility is key, so ensure the label and input are properly associated.