Back

Cómo Crear Formularios Accesibles Usando ShadCN UI

Cómo Crear Formularios Accesibles Usando ShadCN UI

Crear formularios que sean tanto funcionales como accesibles puede ser desafiante. Entre gestionar el estado, manejar la validación y asegurar los atributos ARIA apropiados, los desarrolladores a menudo pasan incontables horas en lo que deberían ser tareas sencillas. ShadCN UI, combinado con React Hook Form y Zod, ofrece una solución poderosa que simplifica la creación de formularios mientras mantiene los estándares de accesibilidad.

Este artículo demuestra cómo construir formularios accesibles con ShadCN UI, integrar ShadCN UI React Hook Form para la gestión de estado, e implementar patrones de validación ShadCN UI Zod que permanecerán relevantes durante años.

Puntos Clave

  • ShadCN UI maneja automáticamente los atributos ARIA y patrones de accesibilidad a través de su sistema de formularios componible
  • La integración con React Hook Form proporciona gestión eficiente del estado con re-renderizados mínimos
  • La validación de esquemas Zod asegura validación de formularios type-safe con mensajes de error claros
  • Los componentes integrados manejan asociaciones de etiquetas, anuncios de errores y navegación por teclado

Entendiendo la Arquitectura de Formularios de ShadCN UI

ShadCN UI proporciona un sistema de formularios componible construido sobre primitivos de React Hook Form y Radix UI. La arquitectura sigue un patrón consistente:

<Form>
  <FormField
    control={form.control}
    name="fieldName"
    render={({ field }) => (
      <FormItem>
        <FormLabel>Field Label</FormLabel>
        <FormControl>
          <Input {...field} />
        </FormControl>
        <FormDescription>Helper text</FormDescription>
        <FormMessage />
      </FormItem>
    )}
  />
</Form>

Esta estructura maneja automáticamente:

  • Generación de ID únicos usando React.useId()
  • Atributos aria-describedby y aria-invalid apropiados
  • Asociaciones de mensajes de error
  • Relaciones etiqueta-input

Configurando Formularios Accesibles con ShadCN UI

Primero, instala los componentes necesarios:

npx shadcn@latest add form input textarea checkbox label

Este comando instala los componentes de ShadCN UI junto con las dependencias de React Hook Form y Zod.

Creando un Esquema de Formulario Básico

Define la estructura de tu formulario usando Zod para validación type-safe:

import { z } from "zod"

const formSchema = z.object({
  name: z.string().min(2, "Name must be at least 2 characters"),
  email: z.string().email("Invalid email address"),
  message: z.string().min(10, "Message must be at least 10 characters"),
  terms: z.boolean().refine((val) => val === true, {
    message: "You must accept the terms"
  })
})

type FormData = z.infer<typeof formSchema>

Implementando el Componente de Formulario

Aquí te mostramos cómo construir un formulario de contacto accesible usando la integración de ShadCN UI React Hook Form:

import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, FormDescription } from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { Checkbox } from "@/components/ui/checkbox"
import { Button } from "@/components/ui/button"

export function ContactForm() {
  const form = useForm<FormData>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      name: "",
      email: "",
      message: "",
      terms: false
    }
  })

  function onSubmit(data: FormData) {
    console.log(data)
  }

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
        <FormField
          control={form.control}
          name="name"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Name</FormLabel>
              <FormControl>
                <Input placeholder="John Doe" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />

        <FormField
          control={form.control}
          name="email"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Email</FormLabel>
              <FormControl>
                <Input type="email" placeholder="john@example.com" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        
        <FormField
          control={form.control}
          name="message"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Message</FormLabel>
              <FormControl>
                <Textarea 
                  placeholder="Your message here..." 
                  className="resize-none" 
                  {...field} 
                />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />

        <FormField
          control={form.control}
          name="terms"
          render={({ field }) => (
            <FormItem className="flex flex-row items-start space-x-3 space-y-0">
              <FormControl>
                <Checkbox 
                  checked={field.value}
                  onCheckedChange={field.onChange}
                />
              </FormControl>
              <div className="space-y-1 leading-none">
                <FormLabel>
                  Accept terms and conditions
                </FormLabel>
              </div>
              <FormMessage />
            </FormItem>
          )}
        />

        <Button type="submit">Submit</Button>
      </form>
    </Form>
  )
}

Características de Accesibilidad Integradas

Los componentes de formulario de ShadCN UI implementan automáticamente patrones de accesibilidad cruciales:

  1. Etiquetado Apropiado: El componente FormLabel usa el atributo htmlFor para asociarse con los controles de formulario
  2. Anuncios de Error: Los componentes FormMessage se vinculan mediante aria-describedby
  3. Estados Inválidos: Los campos reciben automáticamente aria-invalid="true" cuando falla la validación
  4. Navegación por Teclado: Todos los componentes soportan interacciones estándar de teclado

Patrones de Validación Avanzados

Implementa escenarios complejos de validación ShadCN UI Zod:

const advancedSchema = z.object({
  password: z.string()
    .min(8, "Password must be at least 8 characters")
    .regex(/[A-Z]/, "Password must contain at least one uppercase letter")
    .regex(/[a-z]/, "Password must contain at least one lowercase letter")
    .regex(/[0-9]/, "Password must contain at least one number"),
  confirmPassword: z.string()
}).refine((data) => data.password === data.confirmPassword, {
  message: "Passwords don't match",
  path: ["confirmPassword"]
})

Mejores Prácticas para Formularios Accesibles

  1. Siempre Usa Etiquetas: Cada input necesita una etiqueta visible para usuarios de lectores de pantalla
  2. Proporciona Mensajes de Error Claros: Sé específico sobre qué salió mal y cómo solucionarlo
  3. Agrupa Campos Relacionados: Usa fieldset y legend para agrupaciones lógicas
  4. Prueba con Teclado: Asegúrate de que todas las interacciones funcionen sin ratón
  5. Valida al Enviar: Evita validación inline agresiva que interrumpa a los usuarios

Conclusión

ShadCN UI transforma el desarrollo de formularios combinando el poder de la gestión de estado de React Hook Form con la validación type-safe de Zod, todo mientras mantiene la accesibilidad como principio fundamental. La arquitectura de componentes asegura que cada formulario que construyas cumpla con los estándares WCAG sin requerir gestión manual de atributos ARIA.

Siguiendo estos patrones, creas formularios que funcionan para todos, independientemente de sus habilidades o tecnologías asistivas. La belleza de este enfoque radica en su simplicidad: los formularios accesibles se convierten en el estándar, no en una idea tardía.

Preguntas Frecuentes

Aunque técnicamente es posible, los componentes de formulario de ShadCN UI están diseñados para trabajar con React Hook Form. Usarlos sin él significa perder validación automática, gestión de estado y características de accesibilidad que hacen valiosa la librería.

ShadCN UI genera automáticamente IDs únicos, asocia etiquetas con inputs a través de atributos htmlFor, vincula mensajes de error mediante aria-describedby, y establece aria-invalid en errores de validación. Todos los componentes soportan navegación por teclado por defecto.

La validación de Zod se ejecuta solo cuando es necesario, típicamente en eventos blur o submit. El impacto en el rendimiento es mínimo ya que React Hook Form previene re-renderizados innecesarios. Para formularios con cientos de campos, considera usar validación a nivel de campo en lugar de validación a nivel de esquema.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay