TextField
TextField.tsx
import React, { useState, useCallback } from 'react';
import styles from './TextField.module.css';
type TextFieldProps = {
label?: string;
placeholder?: string;
value: string;
onChange: (value: string) => void;
}
const TextField = (props: TextFieldProps) => {
const { label, placeholder, value, onChange } = props;
const [isFocused, setIsFocused] = useState<boolean>(false);
const handleInputChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
onChange(event.target.value);
}, [onChange]);
const handleInputFocus = useCallback(() => {
setIsFocused(true);
}, []);
const handleInputBlur = useCallback(() => {
setIsFocused(false);
}, []);
return (
<div className={styles.container}>
{label && <label className={styles.label}>{label}</label>}
<div className={`${styles.inputWrapper} ${isFocused ? styles.focused : ''}`}>
<input
className={styles.input}
type="text"
placeholder={placeholder}
value={value}
onChange={handleInputChange}
onFocus={handleInputFocus}
onBlur={handleInputBlur}
/>
</div>
</div>
);
}
export default TextField;
Usage
import React, { useState } from 'react';
import TextField from './TextField';
const sampleData = {
firstName: 'John',
lastName: 'Doe',
email: 'johndoe@example.com'
}
const App = () => {
const [firstName, setFirstName] = useState<string>(sampleData.firstName);
const [lastName, setLastName] = useState<string>(sampleData.lastName);
const [email, setEmail] = useState<string>(sampleData.email);
const handleFirstNameChange = (value: string) => {
setFirstName(value);
}
const handleLastNameChange = (value: string) => {
setLastName(value);
}
const handleEmailChange = (value: string) => {
setEmail(value);
}
return (
<div>
<TextField label="First Name" value={firstName} onChange={handleFirstNameChange} />
<TextField label="Last Name" value={lastName} onChange={handleLastNameChange} />
<TextField label="Email" value={email} onChange={handleEmailChange} />
</div>
);
}
export default App;
TextField.module.css
.container {
display: flex;
flex-direction: column;
margin-bottom: 1rem;
}
.label {
font-weight: bold;
margin-bottom: 0.5rem;
}
.inputWrapper {
display: flex;
align-items: center;
border: 1px solid #ddd;
border-radius: 4px;
padding: 0.5rem;
}
.inputWrapper.focused {
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
}
.input {
border: none;
outline: none;
flex: 1;
padding: 0;
margin-left: 0.5rem;
}