Formularios

Patrones para construir formularios accesibles y consistentes.

Estructura base

<form onSubmit={handleSubmit} className="space-y-6">
  {/* Campos agrupados */}
  <div className="grid gap-4 sm:grid-cols-2">
    <Input label="Nombre *" placeholder="Tu nombre" required />
    <Input label="Email *" placeholder="tu@email.com" type="email" required />
  </div>

  {/* Campo de texto largo */}
  <div className="space-y-2">
    <label className="block text-sm font-medium text-zinc-300">
      Mensaje *
    </label>
    <textarea 
      className="w-full rounded-xl border border-zinc-700 bg-zinc-900 
        px-4 py-3 text-sm text-white placeholder:text-zinc-500
        focus:border-blue-500 focus:outline-none focus:ring-2 
        focus:ring-blue-500/20 min-h-[120px] resize-y"
      placeholder="Describe tu proyecto..."
      required
    />
  </div>

  {/* Submit */}
  <Button type="submit" variant="primary" size="lg" className="w-full sm:w-auto">
    Enviar mensaje
  </Button>
</form>

Validación

Mostrar errores inline debajo del campo. Cambiar el borde a rojo. Usar role="alert" para accesibilidad.

// Usar el prop 'error' del componente Input
<Input 
  label="Email" 
  placeholder="tu@email.com"
  error={errors.email?.message} // react-hook-form compatible
/>

// El componente maneja automáticamente:
// ✓ aria-invalid="true"
// ✓ aria-describedby apuntando al mensaje
// ✓ Borde rojo + ring rojo
// ✓ Mensaje con role="alert"

Select

<div className="space-y-2">
  <label className="block text-sm font-medium text-zinc-300">
    Tipo de proyecto
  </label>
  <select className="flex h-11 w-full rounded-xl border border-zinc-700 
    bg-zinc-900 px-4 py-2 text-sm text-white
    focus:border-blue-500 focus:outline-none focus:ring-2 
    focus:ring-blue-500/20 appearance-none"
  >
    <option value="">Selecciona una opción</option>
    <option value="web">Aplicación Web</option>
    <option value="mobile">App Móvil</option>
    <option value="saas">Plataforma SaaS</option>
  </select>
</div>

Lineamientos

  • • Siempre usar label visible — nunca solo placeholder
  • • Marcar campos obligatorios con asterisco (*) en el label
  • • Mostrar errores solo después del primer submit o blur
  • • Usar autocomplete en campos comunes (email, name, tel)
  • • Agrupar campos relacionados en grids de 2 columnas en desktop
  • • Botón de submit siempre al final, con estado loading al enviar