Skip to content

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 BaseModal sobre 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 ​

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 com optional.
  • O botão de enviar diz o que faz: "Salvar contrato", "Enviar para aprovação".

Faça e não faça ​

FaçaNã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 ​