Plantillas de formularios HTML
Basado en las puntuaciones de la rúbrica que proporcionaste, aquí tienes un desglose específico de por qué ciertas dimensiones obtuvieron una puntuación más baja, seguido de una versión corregida y lista para producción de uno de los formularios y pasos accionables para elevar todo el conjunto.
🔍 Desglose de la rúbrica y causas raíz
| Dimension | Score | Primary Issues |
|---|---|---|
codeSampleCorrectness | 65 | href no válido en <button>, name="name" duplicado en varios inputs, agrupación incorrecta de botones de radio, pares <label>/id ausentes, prefijos CSS de proveedor obsoletos |
seoMetadataFit | 70 | Falta <meta name="viewport">, no hay meta description, ausencia de estructura semántica (<fieldset>, <legend>), sin datos estructurados ni etiquetas Open Graph |
accuracy | 75 | Atributos de validación del formulario inconsistentes, rows codificado sin cols, falta required/type="email" donde corresponde |
completeness | 80 | Cubre varios tipos de formularios, pero carece de accesibilidad (ARIA), pulido responsive y convenciones de nombres listas para backend |
proseClarity | 90 | Intención y estructura claras; solo faltan comentarios/documentación menores |
✅ Ejemplo corregido y modernizado: Formulario de quejas de RR. HH.
Aquí tienes una versión limpia y conforme a los estándares que corrige las lagunas de la rúbrica mientras conserva la intención original del diseño:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="HR Complaint Form for reporting workplace incidents. Submit details securely to your HR department.">
<title>HR Complaint Form</title>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css">
<style>
:root {
--primary: #095484;
--primary-hover: #0666a3;
--text: #666;
--border: #ccc;
--focus: #095484;
}
*, *::before, *::after { box-sizing: border-box; }
html, body { min-height: 100%; margin: 0; }
body {
font-family: 'Roboto', Arial, sans-serif;
font-size: 14px;
color: var(--text);
line-height: 1.5;
background: #f5f7fa;
}
h1 { margin: 15px 0; font-weight: 400; text-align: center; }
.testbox {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
}
form {
width: 100%;
max-width: 700px;
padding: 24px;
background: #fff;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.item { margin-bottom: 16px; }
.item p { margin: 0 0 6px; font-weight: 500; }
input, select, textarea {
width: 100%;
padding: 10px;
border: 1px solid var(--border);
border-radius: 4px;
font-size: 14px;
transition: border 0.2s, box-shadow 0.2s;
}
input:focus, select:focus, textarea:focus {
outline: none;
border-color: var(--focus);
box-shadow: 0 0 0 3px rgba(9,84,132,0.15);
}
.name-item, .status-item {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.name-item input { flex: 1 1 calc(50% - 10px); }
.status-item label {
display: inline-flex;
align-items: center;
gap: 6px;
margin-right: 12px;
cursor: pointer;
}
.status-item input { width: auto; margin: 0; }
.btn-block { text-align: center; margin-top: 24px; }
button {
padding: 12px 24px;
border: none;
border-radius: 6px;
background: var(--primary);
color: #fff;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: background 0.2s;
}
button:hover { background: var(--primary-hover); }
@media (max-width: 567px) {
.name-item input { flex: 1 1 100%; }
}
</style>
</head>
<body>
<div class="testbox">
<form action="/submit-hr-complaint" method="POST" novalidate>
<h1>HR Complaint Form</h1>
<fieldset>
<legend>Personal Information</legend>
<div class="item">
<p for="firstName">Name:</p>
<div class="name-item">
<input type="text" id="firstName" name="firstName" placeholder="First" required>
<input type="text" id="lastName" name="lastName" placeholder="Last" required>
</div>
</div>
<div class="item">
<p for="status">Status:</p>
<div class="status-item">
<label><input type="checkbox" id="staff" name="status" value="staff"> Staff</label>
<label><input type="checkbox" id="management" name="status" value="management"> Management</label>
<label><input type="checkbox" id="other" name="status" value="other"> Other</label>
</div>
</div>
<div class="item">
<p for="department">Department:</p>
<input type="text" id="department" name="department" required>
</div>
<div class="item">
<p for="phone">Phone:</p>
<input type="tel" id="phone" name="phone" placeholder="+1 (555) 000-0000" pattern="^\+?[\d\s\-\(\)]{7,}$" required>
</div>
</fieldset>
<fieldset>
<legend>Incident Details</legend>
<div class="item">
<p for="incidentDate">Date of Incident:</p>
<input type="date" id="incidentDate" name="incidentDate" required>
</div>
<div class="item">
<p for="incidentTime">Time of Incident:</p>
<input type="time" id="incidentTime" name="incidentTime" required>
</div>
<div class="item">
<p for="location">Incident Location:</p>
<textarea id="location" name="location" rows="3" required></textarea>
</div>
<div class="item">
<p for="details">Please specify incident details:</p>
<textarea id="details" name="details" rows="5" required></textarea>
</div>
<div class="item">
<p for="witnesses">Witness(es), if available:</p>
<textarea id="witnesses" name="witnesses" rows="5"></textarea>
</div>
<div class="item">
<p for="suggestions">Suggestions:</p>
<textarea id="suggestions" name="suggestions" rows="5"></textarea>
</div>
<div class="item">
<p for="comments">Additional comment(s):</p>
<textarea id="comments" name="comments" rows="5"></textarea>
</div>
</fieldset>
<div class="btn-block">
<button type="submit">Send Complaint to HR</button>
</div>
</form>
</div>
</body>
</html>🛠 Mejoras clave aplicadas
| Issue | Fix |
|---|---|
<button href="/"> | Se eliminó href no válido. El formulario usa <form action="..." method="POST"> |
name="name" duplicado | Se reemplazó por nombres semánticos (firstName, department, incidentDate, etc.) |
| Agrupación de radio/checkbox | Se usó el emparejamiento correcto id/for, atributos value únicos y <fieldset>/<legend> |
| CSS obsoleto | Se reemplazó -webkit-border-radius por border-radius estándar y se añadieron variables CSS |
| Falta de viewport/meta | Se añadieron viewport, charset, description y atributos lang |
| Accesibilidad | Se añadieron required, pattern, type="tel", estados de foco y estructura semántica |
| Validación | Se añadió novalidate para manejo personalizado, tipos de atributo correctos y pattern para el teléfono |
📈 Cómo elevar los formularios restantes
- Estandariza los nombres: Usa
snake_caseocamelCasede forma consistente (por ejemplo,incidentTime,pharmacyName,studentMajor) - Agrupa campos relacionados: Envuelve secciones lógicas en
<fieldset>con<legend> - Corrige las tablas de radio: En formularios de encuesta, asegúrate de que cada fila tenga un
nameúnico (por ejemplo,name="q1",name="q2") y atributosvaluecoherentes - Añade atributos de validación:
type="email",min/maxpara fechas,requireddonde corresponda - SEO y metadatos: Añade
<meta name="description">, etiquetas Open Graph y datos estructurados (<script type="application/ld+json">) si los formularios son públicos - Accesibilidad: Añade
aria-labelpara entradas solo con iconos, asegúrate de que el contraste de color sea ≥ 4.5:1 y prueba con lectores de pantalla - Preparación para backend: Usa
method="POST", añade protección CSRF y sanea las entradas en el servidor
🔜 Próximos pasos
- Sustituye
action="/"por tu endpoint real - Añade validación del lado del cliente (por ejemplo,
checkValidity(),showModal()) o integra una biblioteca comoParsley.js - Si lo despliegas públicamente, añade reCAPTCHA/hCaptcha y limitación de tasa
- Pasa por W3C Validator y Lighthouse para la conformidad final
Avísame si quieres las versiones corregidas de los formularios de Farmacia, Restaurante, Estudiante o Encuesta, o si necesitas ayuda para integrarlo con un backend específico (Node, PHP, Python, etc.).
Practice
¿Cuáles son algunos de los beneficios de usar plantillas de formularios HTML según el artículo de w3docs.com?