Tema
Formulários
Um formulário pede só o necessário, diz o que é obrigatório e mostra cada erro no campo, com o jeito de acertar.
Quando usar
- Cadastro e edição de um registro: contrato, obra, ordem de serviço.
- Formulários curtos (até uns seis campos) vão num
BaseModalsobre a lista. Formulários longos ganham uma tela própria, dividida em seções. - Um processo com etapas que dependem umas das outras usa o
BaseWizard.
Componentes
BaseField: rótulo, ajuda (helper-text),requiredouoptional, e o erro (invalideinvalid-text). Envolve o controle.- Os controles:
BaseInput,BaseSelect,BaseDateInput,BaseMoneyInput,BaseTextarea,BaseCheckbox,BaseRadioGroupeBaseCombobox. BaseFormSection,BaseFormGrideBaseFormGridItem: seções com título e as colunas, que viram uma no celular.BaseAlertBannercomtone="error"elive: o erro do envio, no topo.BaseButtoncomtype="submit"eloading: um botão primário por formulário.
Texto
- Rótulo curto, com o nome que a pessoa usa: "Número do contrato", "Valor inicial com BDI".
- A ajuda diz o formato ou o porquê, antes do erro acontecer: "De 0% a 100%. Reforma 50%, construção 25%."
- O erro diz como acertar: "Informe a data da OS", "A data de fim precisa ser depois da data de início".
- Marque o que é obrigatório com
required. Se quase tudo é obrigatório, marque os poucos opcionais comoptional. - O botão de enviar diz o que faz: "Salvar contrato", "Enviar para aprovação".
Faça e não faça
| Faça | Não faça |
|---|---|
| Mostrar os erros depois da primeira tentativa de enviar, campo por campo. | Marcar tudo de vermelho antes de a pessoa digitar. |
| Levar o foco ao primeiro campo com erro ao enviar. | Só dizer no topo "Há erros no formulário". |
Usar BaseMoneyInput e BaseDateInput para dinheiro e datas. | Um BaseInput de texto com máscara própria. |
Código
vue
<script setup lang="ts">
import { nextTick, reactive, ref } from 'vue'
import {
BaseAlertBanner, BaseButton, BaseDateInput, BaseField, BaseFormGrid, BaseFormGridItem, BaseFormSection,
BaseInput, BaseMoneyInput,
} from '@lab-inovacao-tjes/design-system'
const form = reactive({ number: '', signedOn: '', amountCents: null as number | null })
const tried = ref(false)
const problem = ref('')
const saving = ref(false)
const missing = (value: unknown): boolean => tried.value && (value === null || value === '')
async function submit(): Promise<void> {
tried.value = true
if (!form.number || !form.signedOn || form.amountCents === null) {
await nextTick()
document.querySelector<HTMLElement>('[aria-invalid="true"]')?.focus()
return
}
saving.value = true
problem.value = ''
try {
await contractService.create(form)
} catch {
problem.value = 'Não conseguimos salvar o contrato. Confira a conexão e tente de novo.'
} finally {
saving.value = false
}
}
</script>
<template>
<form novalidate @submit.prevent="submit">
<BaseAlertBanner v-if="problem" tone="error" live>{{ problem }}</BaseAlertBanner>
<BaseFormSection title="Dados do contrato" description="Como estão no contrato assinado.">
<BaseFormGrid>
<BaseFormGridItem>
<BaseField label="Número do contrato" required helper-text="Como no contrato, por exemplo 012/2026." :invalid="missing(form.number)" invalid-text="Informe o número do contrato.">
<BaseInput v-model="form.number" />
</BaseField>
</BaseFormGridItem>
<BaseFormGridItem>
<BaseField label="Data do contrato" required :invalid="missing(form.signedOn)" invalid-text="Informe a data do contrato.">
<BaseDateInput v-model="form.signedOn" />
</BaseField>
</BaseFormGridItem>
<BaseFormGridItem>
<BaseField label="Valor inicial com BDI" required :invalid="missing(form.amountCents)" invalid-text="Informe o valor do contrato.">
<BaseMoneyInput v-model="form.amountCents" />
</BaseField>
</BaseFormGridItem>
</BaseFormGrid>
</BaseFormSection>
<BaseButton type="submit" :loading="saving">Salvar contrato</BaseButton>
</form>
</template>Na tela de referência
- P19, novo contrato:
ContractForm.vue, com seções, colunas, datas e valores. - P19, formulários curtos em modal:
WorkFormModal.vueeSheetFormModal.vue. - P19, erro no campo depois de tentar enviar:
StartOrderForm.vue. - P20: em construção.