Formulär i React: Interaktiv Användarinmatning
Problemet: Statisk HTML räcker inte
Du har byggt en fin statisk webbsida, men nu vill användarna kunna skicka meddelanden, registrera konton eller söka efter produkter. Vanlig HTML-formulär skickar dig till en ny sida - inte så användarvänligt för moderna webbappar.
<!-- Traditionellt HTML-formulär -->
<form action="/submit" method="POST">
<input type="text" name="username" />
<button type="submit">Skicka</button>
</form>
<!-- Sidan laddas om och användaren förlorar sitt sammanhang -->
Problem:
- Sidan laddas om vid varje submit
- Ingen validering innan skickning
- Svårt att ge användaren feedback
- Kan inte kombinera med andra React-komponenter smidigt
Lösningen: Kontrollerade formulär med React
React gör formulär interaktiva genom att låta oss hantera all input i JavaScript och ge omedelbar feedback utan sidladdningar.
Grundprincipen
I React kontrollerar vi formulär-värden med useState
och hanterar ändringar med event handlers. Detta kallas "controlled components".
Steg-för-steg: Bygg interaktiva formulär
Steg 1: Ett enkelt textfält
Låt oss börja med det allra enklaste - en komponent som visar vad användaren skriver medan de skriver:
import { useState } from 'react';
function SimpleForm() {
const [name, setName] = useState('');
return (
<div>
<h2>Hej, {name || 'okänd person'}!</h2>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Skriv ditt namn..."
/>
<p>Du har skrivit: "{name}"</p>
</div>
);
}
Prova detta: Skriv i fältet och se hur texten uppdateras direkt medan du skriver!
Viktiga delar:
value={name}
- React kontrollerar vad som visasonChange
- Körs varje gång användaren skrivere.target.value
- Det nya värdet från input-fältet
Steg 2: Hantera formulär-submit
Nu lägger vi till en submit-knapp och förhindrar sidladdning:
function ContactForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const handleSubmit = (e) => {
e.preventDefault(); // Förhindra sidladdning!
console.log('Formulär skickat:', { name, email });
alert(`Tack ${name}! Vi kontaktar dig på ${email}`);
};
return (
<form onSubmit={handleSubmit} className="contact-form">
<h2>Kontakta oss</h2>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Ditt namn"
className="form-input"
/>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Din e-post"
className="form-input"
/>
<button type="submit" className="submit-button">
Skicka meddelande
</button>
</form>
);
}
Förslag CSS
.contact-form {
max-width: 400px;
margin: 0 auto;
padding: 20px;
}
.form-input {
width: 100%;
padding: 10px;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
.submit-button {
width: 100%;
padding: 12px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
Testa: Fyll i formuläret och klicka "Skicka meddelande"
Steg 3: Lägg till validering
Nu gör vi formuläret smartare med validering:
function ValidatedForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [errors, setErrors] = useState({});
const validateForm = () => {
const newErrors = {};
if (!name.trim()) {
newErrors.name = 'Namn är obligatoriskt';
}
if (!email.trim()) {
newErrors.email = 'E-post är obligatoriskt';
} else if (!email.includes('@')) {
newErrors.email = 'Ange en giltig e-postadress';
}
return newErrors;
};
const handleSubmit = (e) => {
e.preventDefault();
const formErrors = validateForm();
setErrors(formErrors);
if (Object.keys(formErrors).length === 0) {
// Inga fel - skicka formuläret
console.log('Formulär godkänt:', { name, email });
alert('Meddelande skickat!');
// Rensa formuläret
setName('');
setEmail('');
}
};
return (
<form onSubmit={handleSubmit} className="validated-form">
<h2>Kontakta oss</h2>
<div className="form-group">
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Ditt namn"
className={`form-input ${errors.name ? 'error' : ''}`}
/>
{errors.name && <span className="error-message">{errors.name}</span>}
</div>
<div className="form-group">
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Din e-post"
className={`form-input ${errors.email ? 'error' : ''}`}
/>
{errors.email && <span className="error-message">{errors.email}</span>}
</div>
<button type="submit" className="submit-button">
Skicka meddelande
</button>
</form>
);
}
Lägg till CSS för fel:
.form-group {
margin-bottom: 15px;
}
.form-input.error {
border-color: #dc3545;
}
.error-message {
color: #dc3545;
font-size: 14px;
display: block;
margin-top: 5px;
}
Testa: Försök skicka utan att fylla i fälten, eller med ogiltig e-post
Steg 4: Fler formulärelement
Låt oss utöka med olika typer av input:
function CompleteForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
age: '',
country: '',
newsletter: false,
message: ''
});
const handleInputChange = (e) => {
const { name, value, type, checked } = e.target;
setFormData(prev => ({
...prev,
[name]: type === 'checkbox' ? checked : value
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log('Komplett formulär:', formData);
};
return (
<form onSubmit={handleSubmit} className="complete-form">
<h2>Registrera dig</h2>
{/* Textfält */}
<input
type="text"
name="name"
value={formData.name}
onChange={handleInputChange}
placeholder="Namn"
className="form-input"
/>
{/* E-post */}
<input
type="email"
name="email"
value={formData.email}
onChange={handleInputChange}
placeholder="E-post"
className="form-input"
/>
{/* Nummer */}
<input
type="number"
name="age"
value={formData.age}
onChange={handleInputChange}
placeholder="Ålder"
className="form-input"
min="13"
max="120"
/>
{/* Dropdown */}
<select
name="country"
value={formData.country}
onChange={handleInputChange}
className="form-input"
>
<option value="">Välj land</option>
<option value="sweden">Sverige</option>
<option value="norway">Norge</option>
<option value="denmark">Danmark</option>
<option value="finland">Finland</option>
</select>
{/* Checkbox */}
<label className="checkbox-label">
<input
type="checkbox"
name="newsletter"
checked={formData.newsletter}
onChange={handleInputChange}
/>
Jag vill få nyhetsbrev
</label>
{/* Textarea */}
<textarea
name="message"
value={formData.message}
onChange={handleInputChange}
placeholder="Meddelande (valfritt)"
className="form-input"
rows="4"
/>
<button type="submit" className="submit-button">
Registrera
</button>
{/* Debug: visa vad som fylls i */}
<details style={{ marginTop: '20px' }}>
<summary>Debug: Se formulärdata</summary>
<pre>{JSON.stringify(formData, null, 2)}</pre>
</details>
</form>
);
}
Lägg till CSS:
.checkbox-label {
display: flex;
align-items: center;
margin: 10px 0;
cursor: pointer;
}
.checkbox-label input {
margin-right: 8px;
}
textarea.form-input {
resize: vertical;
min-height: 80px;
}
Steg 5: Experimentera själv! 🎯
Nu har du grunderna för React-formulär. Prova att lägga till:
Enkla förbättringar:
// Realtidsvalidering (validera medan användaren skriver)
const handleNameChange = (e) => {
const value = e.target.value;
setName(value);
if (value.length < 2) {
setNameError('Namnet måste vara minst 2 tecken');
} else {
setNameError('');
}
};
// Räkna tecken i textarea
<div>
<textarea /* ... */ />
<small>{message.length}/500 tecken</small>
</div>
// Disable knapp tills formuläret är giltigt
<button
type="submit"
disabled={!name || !email || errors.name}
className="submit-button"
>
Skicka
</button>
Medelsvåra utmaningar:
- Lösenordsstyrka: Visa färgad indikator för lösenordsstyrka
- Bekräfta lösenord: Kontrollera att två lösenordsfält matchar
- Fil-upload: Hantera filuppladdning med preview
- Steg-för-steg formulär: Dela upp i flera steg/sidor
Avancerade idéer:
- Auto-save: Spara formulärdata i localStorage medan användaren skriver
- Async validering: Kontrollera om e-post redan finns (simulera API-anrop)
- Dynamiska fält: Lägg till/ta bort fält baserat på användarens val
Populära formulärbibliotek
När dina formulär blir mer komplexa finns det hjälpsamma bibliotek:
- React Hook Form: Prestanda-optimerat, minimal re-rendering
- Formik: Populärt val med bra validering
- React Final Form: Flexibelt och kraftfullt
Men lär dig grunderna först - förståelse för kontrollerade komponenter är grunden för allt formulärarbete i React!
Viktiga takeaways
✅ Controlled components: React kontrollerar formulärvärdena via state
✅ preventDefault(): Förhindra sidladdning vid submit
✅ Validering: Ge användaren omedelbar feedback
✅ Olika input-typer: text, email, number, select, checkbox, textarea
✅ Användarvänlighet: Tydliga felmeddelanden och visuell feedback
Formulär är en av React:s största styrkor - du kan skapa riktigt interaktiva upplevelser! 🚀