Como Criar Formulários Acessíveis Usando ShadCN UI

Construir formulários que sejam funcionais e acessíveis pode ser desafiador. Entre gerenciar estado, lidar com validação e garantir atributos ARIA adequados, desenvolvedores frequentemente gastam inúmeras horas no que deveriam ser tarefas diretas. ShadCN UI, combinado com React Hook Form e Zod, oferece uma solução poderosa que simplifica a criação de formulários mantendo os padrões de acessibilidade.
Este artigo demonstra como construir formulários acessíveis com ShadCN UI, integrar ShadCN UI React Hook Form para gerenciamento de estado, e implementar padrões de validação ShadCN UI Zod que permanecerão relevantes por anos.
Principais Pontos
- ShadCN UI automaticamente lida com atributos ARIA e padrões de acessibilidade através de seu sistema de formulários composáveis
- A integração com React Hook Form fornece gerenciamento eficiente de estado com re-renderizações mínimas
- A validação de schema Zod garante validação de formulários type-safe com mensagens de erro claras
- Componentes integrados lidam com associações de labels, anúncios de erro e navegação por teclado
Entendendo a Arquitetura de Formulários do ShadCN UI
ShadCN UI fornece um sistema de formulários composável construído sobre primitivos do React Hook Form e Radix UI. A arquitetura segue um padrão 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 estrutura automaticamente lida com:
- Geração de ID único usando
React.useId()
- Atributos
aria-describedby
earia-invalid
adequados - Associações de mensagens de erro
- Relacionamentos label-input
Configurando Formulários Acessíveis com ShadCN UI
Primeiro, instale os componentes necessários:
npx shadcn@latest add form input textarea checkbox label
Este comando instala componentes ShadCN UI junto com as dependências React Hook Form e Zod.
Criando um Schema Básico de Formulário
Defina a estrutura do seu formulário usando Zod para validação type-safe:
import { z } from "zod"
const formSchema = z.object({
name: z.string().min(2, "Nome deve ter pelo menos 2 caracteres"),
email: z.string().email("Endereço de email inválido"),
message: z.string().min(10, "Mensagem deve ter pelo menos 10 caracteres"),
terms: z.boolean().refine((val) => val === true, {
message: "Você deve aceitar os termos"
})
})
type FormData = z.infer<typeof formSchema>
Implementando o Componente de Formulário
Aqui está como construir um formulário de contato acessível usando a integração 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>Nome</FormLabel>
<FormControl>
<Input placeholder="João Silva" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input type="email" placeholder="joao@exemplo.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="message"
render={({ field }) => (
<FormItem>
<FormLabel>Mensagem</FormLabel>
<FormControl>
<Textarea
placeholder="Sua mensagem aqui..."
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>
Aceitar termos e condições
</FormLabel>
</div>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Enviar</Button>
</form>
</Form>
)
}
Discover how at OpenReplay.com.
Recursos de Acessibilidade Integrados
Os componentes de formulário do ShadCN UI implementam automaticamente padrões cruciais de acessibilidade:
- Rotulagem Adequada: O componente
FormLabel
usa o atributohtmlFor
para associar com controles de formulário - Anúncios de Erro: Componentes
FormMessage
são vinculados viaaria-describedby
- Estados Inválidos: Campos automaticamente recebem
aria-invalid="true"
quando a validação falha - Navegação por Teclado: Todos os componentes suportam interações padrão de teclado
Padrões Avançados de Validação
Implemente cenários complexos de validação ShadCN UI Zod:
const advancedSchema = z.object({
password: z.string()
.min(8, "Senha deve ter pelo menos 8 caracteres")
.regex(/[A-Z]/, "Senha deve conter pelo menos uma letra maiúscula")
.regex(/[a-z]/, "Senha deve conter pelo menos uma letra minúscula")
.regex(/[0-9]/, "Senha deve conter pelo menos um número"),
confirmPassword: z.string()
}).refine((data) => data.password === data.confirmPassword, {
message: "Senhas não coincidem",
path: ["confirmPassword"]
})
Melhores Práticas para Formulários Acessíveis
- Sempre Use Labels: Todo input precisa de um label visível para usuários de leitores de tela
- Forneça Mensagens de Erro Claras: Seja específico sobre o que deu errado e como corrigir
- Agrupe Campos Relacionados: Use
fieldset
elegend
para agrupamentos lógicos - Teste com Teclado: Garanta que todas as interações funcionem sem mouse
- Valide no Submit: Evite validação inline agressiva que interrompe usuários
Conclusão
ShadCN UI transforma o desenvolvimento de formulários combinando o poder do gerenciamento de estado do React Hook Form com a validação type-safe do Zod, tudo isso mantendo a acessibilidade como princípio fundamental. A arquitetura de componentes garante que todo formulário que você construa atenda aos padrões WCAG sem exigir gerenciamento manual de atributos ARIA.
Seguindo esses padrões, você cria formulários que funcionam para todos—independentemente de suas habilidades ou tecnologias assistivas. A beleza desta abordagem está em sua simplicidade: formulários acessíveis se tornam o padrão, não uma reflexão tardia.
FAQs
Embora tecnicamente possível, os componentes de formulário do ShadCN UI são projetados para funcionar com React Hook Form. Usá-los sem isso significa perder validação automática, gerenciamento de estado e recursos de acessibilidade que tornam a biblioteca valiosa.
ShadCN UI automaticamente gera IDs únicos, associa labels com inputs através de atributos htmlFor, vincula mensagens de erro via aria-describedby, e define aria-invalid em erros de validação. Todos os componentes suportam navegação por teclado por padrão.
A validação Zod executa apenas quando necessário, tipicamente em eventos blur ou submit. O impacto na performance é mínimo já que React Hook Form previne re-renderizações desnecessárias. Para formulários com centenas de campos, considere usar validação em nível de campo ao invés de validação em nível de schema.
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.