Build a controlled form with multiple fields and a checkbox. On submit, show collected data and reset the form.
Business case. LeadCapture — mini lead form: name, email, message and newsletter consent.
onChange.onSubmit, assemble the data object and display it below.A card with form fields, checkbox, submit button, and a “Submitted” block.
Preview:

const [name, setName] = useState(''), similarly for others.disabled={!name.trim() || !email.trim()}.onSubmit: e.preventDefault(); collect { name, email, message, subscribe }, display, and reset fields.canSubmit to a variable for readability.import React, { useState } from 'react';
import './styles.css';
export function FeedbackForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [message, setMessage] = useState('');
const [subscribe, setSubscribe] = useState(false);
const [submitted, setSubmitted] = useState(null);
function handleSubmit(e) {
e.preventDefault();
const canSubmit = name.trim() && email.trim();
if (!canSubmit) return;
setSubmitted({ name, email, message, subscribe });
setName('');
setEmail('');
setMessage('');
setSubscribe(false);
}
const canSubmit = name.trim() && email.trim();
return (
<article className="card" data-testid="form-card">
<header>
<h2 className="title">LeadCapture: feedback form</h2>
<p className="subtitle">Controlled inputs + checkbox, submit action</p>
</header>
<form className="row" onSubmit={handleSubmit} aria-label="form">
<input
className="input"
type="text"
placeholder="Name"
value={name}
onChange={(e) => setName(e.target.value)}
aria-label="name"
/>
<input
className="input"
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
aria-label="email"
/>
<textarea
className="textarea"
placeholder="Message"
value={message}
onChange={(e) => setMessage(e.target.value)}
aria-label="message"
rows={3}
/>
<label className="checkbox-row">
<input
className="checkbox"
type="checkbox"
checked={subscribe}
onChange={(e) => setSubscribe(e.target.checked)}
aria-label="subscribe"
/>
<span>Subscribe to newsletter</span>
</label>
<div className="actions">
<button className="button" type="submit" disabled={!canSubmit}>Submit</button>
</div>
</form>
{submitted && (
<section className="result" aria-label="result">
<p><strong>Submitted:</strong></p>
<p>Name: {submitted.name}</p>
<p>Email: {submitted.email}</p>
<p>Message: {submitted.message}</p>
<p>Subscribed: {submitted.subscribe ? 'Yes' : 'No'}</p>
</section>
)}
</article>
);
}
export default function App() {
return (
<main className="challenge-container">
<section>
<FeedbackForm />
</section>
</main>
);
}Build a controlled form with multiple fields and a checkbox. On submit, show collected data and reset the form.
Business case. LeadCapture — mini lead form: name, email, message and newsletter consent.
onChange.onSubmit, assemble the data object and display it below.A card with form fields, checkbox, submit button, and a “Submitted” block.
Preview:

const [name, setName] = useState(''), similarly for others.disabled={!name.trim() || !email.trim()}.onSubmit: e.preventDefault(); collect { name, email, message, subscribe }, display, and reset fields.canSubmit to a variable for readability.import React, { useState } from 'react';
import './styles.css';
export function FeedbackForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [message, setMessage] = useState('');
const [subscribe, setSubscribe] = useState(false);
const [submitted, setSubmitted] = useState(null);
function handleSubmit(e) {
e.preventDefault();
const canSubmit = name.trim() && email.trim();
if (!canSubmit) return;
setSubmitted({ name, email, message, subscribe });
setName('');
setEmail('');
setMessage('');
setSubscribe(false);
}
const canSubmit = name.trim() && email.trim();
return (
<article className="card" data-testid="form-card">
<header>
<h2 className="title">LeadCapture: feedback form</h2>
<p className="subtitle">Controlled inputs + checkbox, submit action</p>
</header>
<form className="row" onSubmit={handleSubmit} aria-label="form">
<input
className="input"
type="text"
placeholder="Name"
value={name}
onChange={(e) => setName(e.target.value)}
aria-label="name"
/>
<input
className="input"
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
aria-label="email"
/>
<textarea
className="textarea"
placeholder="Message"
value={message}
onChange={(e) => setMessage(e.target.value)}
aria-label="message"
rows={3}
/>
<label className="checkbox-row">
<input
className="checkbox"
type="checkbox"
checked={subscribe}
onChange={(e) => setSubscribe(e.target.checked)}
aria-label="subscribe"
/>
<span>Subscribe to newsletter</span>
</label>
<div className="actions">
<button className="button" type="submit" disabled={!canSubmit}>Submit</button>
</div>
</form>
{submitted && (
<section className="result" aria-label="result">
<p><strong>Submitted:</strong></p>
<p>Name: {submitted.name}</p>
<p>Email: {submitted.email}</p>
<p>Message: {submitted.message}</p>
<p>Subscribed: {submitted.subscribe ? 'Yes' : 'No'}</p>
</section>
)}
</article>
);
}
export default function App() {
return (
<main className="challenge-container">
<section>
<FeedbackForm />
</section>
</main>
);
}The code editor is intentionally hidden on mobile.
Believe me, it's for the best: I am protecting you from the temptation to code in less-than-ideal conditions. A small screen and a virtual keyboard are not the best tools for a programmer.
📖 Now: Study the task, think through the solution. Act like a strategist.
💻 Later: Sit down at your computer, open the site, and implement all your ideas comfortably. Act like a code-jedi!