Tema
BaseFormSection e BaseFormGrid
Organizam um formulário longo. BaseFormSection divide o formulário em partes com título e descrição. BaseFormGrid põe os campos em duas colunas, que viram uma só em telas com menos de 768 px. BaseFormGridItem faz um campo ocupar a linha inteira.
Uso
- Divida em seções quando o formulário passa de seis ou sete campos, ou quando os campos tratam de assuntos diferentes: identificação, valores, responsáveis.
- O título da seção é um substantivo curto ("Valores e prazos"). A descrição, opcional, diz em uma linha o que a seção pede ou por que importa.
- Coloque as seções direto no formulário com a classe
tj-form, que é o cartão: superfície--tj-layer-01, borda e raio. Cada seção já tem o próprio recuo, e uma linha separa uma da outra. - Um interruptor que muda o formulário inteiro (por exemplo, "Contrato por demanda") pode ficar numa caixa própria na linha inteira:
<div class="tj-switch-box tj-span-2">com umBaseSwitchdentro. - Na grade, ponha lado a lado campos curtos que se leem juntos, como número e processo. Campos longos (objeto, observações) ocupam a linha inteira.
- Siga a ordem de leitura: da esquerda para a direita, linha por linha. A ordem do Tab é a ordem do código, então escreva os campos na ordem em que aparecem.
heading-levelsegue o esquema da página. Com o título da página em<h1>, as seções ficam em<h2>(o padrão); dentro de um painel que já tem<h2>, use3.
Linha inteira
Há duas formas de um filho ocupar as duas colunas:
vue
<BaseFormGridItem :span="2">
<BaseField label="Objeto"><BaseInput /></BaseField>
</BaseFormGridItem>
<BaseField class="tj-span-2" label="Objeto"><BaseInput /></BaseField>A classe tj-span-2 serve para qualquer filho direto da grade e não cria um elemento a mais. BaseFormGridItem é útil quando o filho não aceita class ou quando a largura vem de uma variável (:span="largo ? 2 : 1").
Estilo
| Propriedade | Token |
|---|---|
Cartão (tj-form) | fundo --tj-layer-01, borda 1 px --tj-border-subtle-02, raio --tj-radius-lg, --tj-shadow-1; o conteúdo é cortado no raio |
| Recuo da seção | --tj-space-6; abaixo de 576 px, --tj-space-4 |
| Separador entre seções | 1 px --tj-border-subtle-01 |
| Espaço cabeçalho → campos | --tj-space-5 |
| Título | tj-h4: --tj-text-lg, semibold, --tj-text-primary |
| Título → descrição | --tj-space-1 |
| Descrição | --tj-text-helper, --tj-text-sm |
| Colunas | 2 a partir de 768 px; 1 abaixo |
| Espaço entre linhas | --tj-space-5 |
| Espaço entre colunas | --tj-space-6 |
Caixa de interruptor (tj-switch-box) | fundo --tj-layer-02, borda 1 px --tj-border-subtle-02, raio --tj-radius-md, recuo --tj-space-4 |
Diferença em relação ao protótipo v3: lá a grade virava uma coluna abaixo de 576 px; aqui vira abaixo de 768 px, o ponto md do Bootstrap, para que um tablet em pé já mostre uma coluna. O recuo da seção continua mudando em 576 px. O par tj-card tj-form do protótipo virou só tj-form, que já traz a superfície do cartão. Em tj-switch-box, o recuo da ajuda saiu: o BaseSwitch já alinha a ajuda ao texto.
Código
vue
<form class="tj-form" aria-label="Dados do contrato" novalidate>
<BaseFormSection title="Identificação" description="Como o contrato aparece no SEI.">
<BaseFormGrid>
<BaseField label="Número do contrato" required><BaseInput v-model="numero" /></BaseField>
<BaseField label="Processo SEI" required><BaseInput v-model="sei" /></BaseField>
<BaseFormGridItem :span="2">
<BaseField label="Objeto" required><BaseInput v-model="objeto" /></BaseField>
</BaseFormGridItem>
</BaseFormGrid>
</BaseFormSection>
</form>BaseFormSection
| Propriedade | Tipo | Padrão | Descrição |
|---|---|---|---|
title | string | — | Título da seção (obrigatório); também dá nome à região |
description | string | — | Uma linha sob o título |
headingLevel | 2 | 3 | 4 | 5 | 6 | 2 | Nível semântico do título; a aparência não muda |
Slot padrão: o conteúdo da seção, em geral uma BaseFormGrid.
BaseFormGrid
Sem propriedades. Slot padrão: os campos.
BaseFormGridItem
| Propriedade | Tipo | Padrão | Descrição |
|---|---|---|---|
span | 1 | 2 | 1 | Colunas que o item ocupa; 2 é a linha inteira |
Nenhum dos três emite eventos.
Acessibilidade
- Cada seção é um
<section>nomeado pelo próprio título (aria-labelledby), e a descrição fica emaria-describedby. O leitor de tela lista as seções como regiões e permite pular de uma para outra; o título também aparece na lista de cabeçalhos. - O título é um cabeçalho de verdade (
<h2>por padrão), então o esquema da página fica correto. Não pule níveis: ajusteheading-levelao lugar onde o formulário está. - A grade é só visual: um
<div>sem papel ARIA. A ordem de leitura e do Tab é a ordem dos campos no código, a mesma da tela em uma ou em duas colunas. - Abaixo de 768 px a grade vira uma coluna, o que também vale para zoom alto no computador: os campos não ficam espremidos lado a lado (WCAG 1.4.10).
- Não há animação nem estado interativo; o foco e os estados ficam com cada campo.
- Testado com axe com campos dentro, em todas as variações, e com duas seções no mesmo formulário (regiões com nomes diferentes e títulos no mesmo nível). O axe roda sem layout, então o contraste é conferido na documentação renderizada, em tema claro e escuro.