Padrão de Formulário com Envio de API
Este padrão define como implementar formulários que interagem com APIs, estabelecendo convenções claras para labels de botões baseadas no comportamento de envio dos dados. O objetivo é criar consistência na interface e comunicar claramente ao usuário o que acontecerá quando ele submeter o formulário.
Contexto & Problema
Section titled “Contexto & Problema”Em interfaces que interagem com APIs, diferentes tipos de operações podem confundir o usuário sobre o que realmente acontece quando um formulário é submetido. A falta de padronização nas labels dos botões pode gerar incertezas sobre se os dados serão salvos imediatamente ou processados posteriormente.
Quando Usar
Section titled “Quando Usar”- Para formulários que fazem chamadas diretas para API
- Quando há necessidade de distinguir entre salvamento imediato e processamento posterior
- Em interfaces que precisam de feedback claro sobre o tipo de operação sendo realizada
Componentes Utilizados
Section titled “Componentes Utilizados”- Button (Console Kit Blocks)
- Form (Console Kit Blocks)
- Loading States (Console Kit Blocks)
Exemplo Visual
Section titled “Exemplo Visual”
Formulário com botão “Save” para operações imediatas

Formulário com botão “Apply” para operações em fila
Comportamento Esperado
Section titled “Comportamento Esperado”- “Save”: Usar quando o formulário envia dados diretamente para a API e os dados são processados/salvos imediatamente
- “Apply”: Usar quando o formulário registra dados para processamento posterior ou em fila
- Consistência: Manter a mesma label para operações similares em toda a aplicação
- Estado normal: Label apropriada (“Save” ou “Apply”)
- Estado loading: Mostrar indicador de carregamento durante o envio
- Estado disabled: Desabilitar durante processamento para evitar múltiplos envios
- Estado de sucesso: Feedback visual após conclusão da operação
Implementação
Section titled “Implementação”const FormSubmissionHandler = { // Determina a label baseada no tipo de operação getButtonLabel: (operationType) => { switch (operationType) { case 'immediate': return 'Save'; case 'queued': case 'deferred': return 'Apply'; default: return 'Submit'; } },
// Gerencia o estado do botão durante o envio handleSubmission: async (formData, operationType) => { const button = document.querySelector('[data-submit-button]'); const originalLabel = button.textContent;
try { // Estado de loading button.disabled = true; button.innerHTML = '<span class="loading-spinner"></span> Processing...';
// Envio para API const response = await fetch('/api/submit', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...formData, operationType }) });
if (response.ok) { // Feedback de sucesso button.textContent = operationType === 'immediate' ? 'Saved!' : 'Applied!'; setTimeout(() => { button.textContent = originalLabel; button.disabled = false; }, 2000); } } catch (error) { // Estado de erro button.textContent = 'Error - Try Again'; button.disabled = false; } }};
// Exemplo de usoconst form = document.querySelector('#custom-page-form');form.addEventListener('submit', (e) => { e.preventDefault(); const formData = new FormData(form); const operationType = form.dataset.operationType || 'immediate';
FormSubmissionHandler.handleSubmission( Object.fromEntries(formData), operationType );});Boas Práticas
Section titled “Boas Práticas”Anti-padrões
Section titled “Anti-padrões”Acessibilidade
Section titled “Acessibilidade”- Utilize
aria-labelpara descrever a ação específica do botão - Implemente
aria-liveregions para anunciar mudanças de estado - Garanta que estados de loading sejam anunciados por leitores de tela
- Mantenha contraste adequado em todos os estados do botão