Skip to content
Versão preliminar. Cores, componentes e layout ainda vão mudar: falta receber o padrão de interface do TJES (template-basico-vue) e o manual de identidade visual.

BaseWizard ​

Guia um cadastro longo, uma etapa por vez: o andamento fica no alto, a etapa atual no meio e os botões Voltar, Continuar e Concluir no rodapé. Antes de avançar, o assistente confere a etapa.

  1. Dados do contrato, etapa atual
  2. Planilha vencedora, etapa pendente
  3. Empenho, etapa pendente
  4. Revisão, etapa pendente

Etapa 1 de 4: Dados do contrato

Identificação, objeto e prazos.

Formato CF000/AAAA.

Experimente avançar com o número vazio: a etapa fica, o campo mostra o erro e recebe o foco, e o andamento marca a etapa com erro.

Uso ​

  • Use para um cadastro longo que se divide em partes com começo e fim claros: cadastro de contrato, lançamento de medição. Para mostrar onde um documento está num fluxo fixo, sem preencher nada, use o BaseStatusFlow.
  • De três a cinco etapas. Com duas, um formulário só com seções (BaseFormSection) resolve; com mais de cinco, junte etapas.
  • O nome da etapa diz o que ela pede, com as palavras da tela: "Planilha vencedora", não "Passo 2".
  • O conteúdo de cada etapa vai no slot step-<id>, com o id da etapa: #step-contrato, #step-planilha. Só a etapa atual fica montada, então guarde os dados no componente pai.
  • O v-model é o id da etapa atual. Um id vazio ou desconhecido mostra a primeira etapa.
  • validate recebe o id da etapa e devolve true para avançar ou false para ficar. Pode ser assíncrono: enquanto roda, Continuar fica ocupado. Se a função lançar erro, a etapa fica e o assistente emite error com o erro, para o pai registrar ou explicar a falha.
  • Se a etapa mudar ou o assistente for desabilitado enquanto validate roda, o resultado é descartado: nenhuma etapa avança sem ter sido conferida.
  • Ao falhar, marque os campos com invalid e uma mensagem que diga como corrigir: o foco vai para o primeiro campo com aria-invalid="true"; num grupo de opções (BaseRadioGroup), para a opção marcada ou a primeira.
  • Sem campo marcado, por exemplo numa regra da etapa inteira ou numa falha de rede, a etapa mostra um aviso de erro com errorText logo abaixo do título. Para uma causa conhecida, passe um errorText que diga o que fazer, como "A planilha tem itens sem preço unitário.".
  • Voltar não confere a etapa: ninguém fica preso por um campo que ainda vai corrigir.
  • O último botão é Concluir e dispara complete. Enquanto salva, passe loading.
  • Ações de apoio, como "Salvar rascunho", vão no slot actions, no começo do rodapé. Use BaseButton, que já é type="button", ou type="button" num botão comum: um <button> sem tipo envia o formulário e aciona Continuar.
  • A etapa já é um <form>: não ponha outro <form> dentro de um slot de etapa.
  • Uma etapa com muitos campos se divide em BaseFormSection dentro do slot; o assistente tira o recuo próprio da seção e mantém a linha entre elas.

Estados ​

  1. Dados do contrato, etapa concluída
  2. Planilha vencedora, etapa com erro
  3. Empenho, etapa pendente
  4. Revisão, etapa pendente

Etapa 2 de 4: Planilha vencedora

Excel da licitação.

A planilha tem 3 itens sem preço unitário.

  1. Dados do contrato, etapa concluída
  2. Planilha vencedora, etapa concluída
  3. Empenho, etapa concluída
  4. Revisão, etapa atual

Etapa 4 de 4: Revisão

Confira e salve.

Salvando o contrato.

  1. Dados do contrato, etapa concluída
  2. Planilha vencedora, etapa atual
  3. Empenho, etapa pendente
  4. Revisão, etapa pendente

Etapa 2 de 4: Planilha vencedora

Excel da licitação.

Carregando a planilha.

EstadoComo aparece
Etapa atualAnel azul com ponto no andamento e "Etapa 2 de 4" no cartão; o nome da etapa no título
Etapa com erroDepois de validate falhar, ou com invalid: círculo com exclamação e nome em vermelho; o leitor de tela ouve "etapa com erro". Some quando a etapa muda
Falha sem campo marcadovalidate falhou ou lançou erro sem campo com aria-invalid: aviso de erro (BaseAlertBanner) com errorText abaixo do título. Some na próxima tentativa ou quando a etapa muda
Conferindo ou salvandoloading, ou validate assíncrono em curso: o botão principal mostra o giro, diz "ocupado" e ignora cliques; Voltar espera
Desabilitadodisabled: Voltar e Continuar desabilitados, por exemplo enquanto a etapa carrega

Estilo ​

PropriedadeToken
Cartões do andamento e da etapaFundo --tj-layer-01, borda 1 px --tj-border-subtle-02, raio --tj-radius-lg, sombra --tj-shadow-1
Cartão do andamentoRecuo --tj-space-5 --tj-space-6 (--tj-space-4 no celular), --tj-space-3 entre "Etapa 1 de 4" e a lista
"Etapa 1 de 4"No cartão do andamento: --tj-text-xs, --tj-weight-semibold, caixa alta, --tj-link-primary (6,53:1 no claro, 7,59:1 no escuro)
Nome da etapaEstilo tj-h3 (--tj-text-xl, --tj-weight-semibold)
Descrição--tj-text-sm, --tj-text-helper (5,80:1 no claro, 7,49:1 no escuro)
RodapéFundo --tj-layer-02, borda superior 1 px --tj-border-subtle-01, --tj-space-3 entre botões, cantos de baixo com --tj-radius-lg menos a borda
Espaço--tj-space-4 entre os cartões; --tj-space-6 dentro da etapa (--tj-space-4 no celular)
AndamentoO do BaseStatusFlow, tamanho médio
Foco--tj-ring nos botões e no título da etapa

Os contrastes são do texto contra --tj-layer-01, calculados a partir dos tokens nos dois temas.

Troca em relação ao protótipo v3: o .tj-wizard do protótipo (faixas no alto com "Etapa N") virou o BaseStatusFlow, para o andamento ter a mesma forma, os mesmos sinais e o mesmo texto para o leitor de tela em todo o sistema. A posição "Etapa 1 de 4" aparece no cartão do andamento, acima da lista; o leitor de tela a ouve no título da etapa, então no cartão ela fica escondida dele (aria-hidden).

O cartão da etapa não corta o conteúdo (overflow visível), para a lista de um BaseCombobox perto do fim da etapa passar da borda; o rodapé arredonda os próprios cantos.

No celular (até 575 px), os botões dividem a linha, cada um com a mesma largura, e o principal fica à direita.

Código ​

vue
<script setup lang="ts">
import { ref } from 'vue'
import { BaseField, BaseInput, BaseWizard, type WizardStep } from '@lab-inovacao/design-system'

const etapas: WizardStep[] = [
  { id: 'contrato', label: 'Dados do contrato', description: 'Identificação, objeto e prazos.' },
  { id: 'planilha', label: 'Planilha vencedora' },
  { id: 'revisao', label: 'Revisão' },
]
const etapa = ref('contrato')
const numero = ref('')
const numeroInvalido = ref(false)

function conferir(id: string): boolean {
  if (id !== 'contrato') return true
  numeroInvalido.value = numero.value.trim() === ''
  return !numeroInvalido.value
}

function salvar(): void {
  // salva o contrato
}

function registrar(erro: unknown): void {
  console.error('Falha ao conferir a etapa', erro)
}
</script>

<template>
  <BaseWizard v-model="etapa" label="Etapas do cadastro" :steps="etapas" :validate="conferir" @complete="salvar" @error="registrar">
    <template #step-contrato>
      <BaseField label="Número do contrato" required :invalid="numeroInvalido" invalid-text="Informe o número do contrato.">
        <BaseInput v-model="numero" />
      </BaseField>
    </template>
    <template #step-planilha>…</template>
    <template #step-revisao>…</template>
  </BaseWizard>
</template>
PropriedadeTipoPadrãoDescrição
stepsWizardStep[]—Etapas em ordem, cada uma com id único; obrigatório. Sem etapas, nada aparece
labelstring—Nome da lista do andamento para o leitor de tela; obrigatório
v-modelstringprimeira etapaid da etapa atual
validate(id: string) => boolean | Promise<boolean>—Confere a etapa antes de Continuar e Concluir; false ou erro mantém a etapa
headingLevel2 | 3 | 4 | 5 | 62Nível do título da etapa; a aparência fica tj-h3
invalidbooleanfalseMarca a etapa atual com erro no andamento
disabledbooleanfalseDesabilita Voltar e Continuar
loadingbooleanfalseBotão principal ocupado, Voltar espera
backLabelstring'Voltar'Texto do botão de voltar
nextLabelstring'Continuar'Texto do botão de avançar, como "Continuar para a planilha"
finishLabelstring'Concluir'Texto do botão da última etapa, como "Salvar contrato"
errorTextstring'Não foi possível continuar. Revise a etapa e tente de novo.'Aviso na etapa quando a conferência falha sem campo marcado

WizardStep:

CampoTipoDescrição
idstringChave estável e única; dá o nome do slot step-<id>
labelstringNome da etapa, no andamento e no título
descriptionstringOpcional. Uma linha embaixo do título sobre o que a etapa pede
SlotConteúdo
step-<id>Conteúdo da etapa com esse id
actionsBotões de apoio no começo do rodapé, como "Salvar rascunho"
EventoQuando
update:modelValueContinuar passou na conferência, ou Voltar foi acionado; traz o id da nova etapa
completeConcluir passou na conferência na última etapa
errorvalidate lançou erro ou rejeitou; traz o erro. A etapa fica e mostra errorText

Acessibilidade ​

  • O andamento é o BaseStatusFlow: lista ordenada com o nome do label, a etapa atual com aria-current="step" e cada etapa com o texto da situação ("etapa concluída", "etapa atual", "etapa pendente", "etapa com erro"). A cor nunca vem sozinha: cada situação tem um sinal de forma própria.
  • A etapa é um <form> com o nome do título, "Etapa 2 de 4: Planilha vencedora", e a descrição em aria-describedby. O leitor de tela ouve a posição e o nome juntos.
  • Quando Voltar ou Continuar muda a etapa, o foco vai para o título (tabindex="-1"): o leitor de tela anuncia a nova etapa e quem usa teclado começa do alto dela. Uma troca feita pelo pai move o foco só se ele já estiver dentro do assistente. Ao abrir a tela, ao retomar um rascunho depois de carregar, ou ao inserir uma etapa antes da atual, o foco não se move.
  • Enter num campo aciona Continuar, como em qualquer formulário. Voltar não envia o formulário; no slot actions e dentro das etapas, use BaseButton (que já é type="button") ou type="button", senão o botão aciona Continuar.
  • Se a conferência falhar, o foco vai para o primeiro campo com aria-invalid="true", onde está a mensagem de erro (WCAG 3.3.1); num BaseRadioGroup inválido, para a opção marcada ou a primeira.
  • Sem campo marcado, o foco vai para o título da etapa e logo abaixo aparece o aviso de erro com errorText, em role="alert": quem está no rodapé ouve que não avançou, e quem enxerga vê o aviso com ícone e texto, não só a cor do andamento (WCAG 3.3.1 e 4.1.3).
  • Enquanto confere ou salva, o botão principal continua no foco, recebe aria-busy="true" e ignora cliques e Enter, para ninguém avançar duas vezes.
  • Voltar não aparece na primeira etapa, em vez de aparecer desabilitado.
  • A etapa troca no lugar, sem animação. O único movimento é o giro do botão ocupado, que vem do BaseButton.
  • Testado com axe na primeira, numa do meio e na última etapa, com erro, desabilitado, salvando, conferindo numa etapa do meio, com outro nível de título, com campo inválido depois de uma conferência que falhou e com o aviso de falha sem campo marcado. O contraste foi calculado a partir dos tokens nos dois temas (veja Estilo), porque o jsdom não calcula cores.