Ir para o conteúdo principal
WBC - GovBR-DS
Copiar página como Markdown para IA

Vue – @govbr-ds/webcomponents-vue

Este wrapper Vue encapsula os Web Components GovBR-DS, permitindo que sejam utilizados como componentes nativos no Vue.

Compatibilidade​

  • Faixa declarada: Vue 3, conforme as peerDependencies do pacote.
  • Núcleo de Web Components: @govbr-ds/webcomponents na mesma versão deste wrapper.
  • Navegadores: A mesma política Baseline Widely Available dos Web Components. Internet Explorer não é suportado.

[!NOTE] Essa faixa acompanha o peer exigido pelo runtime do output target Vue. O Vue Router não é um requisito do wrapper. O wrapper não faz requisições HTTP, autenticação, cache ou transporte de dados — essas responsabilidades permanecem na aplicação consumidora.

Por que usar este wrapper? 🤔​

  • Verificação de tipos.
  • Integração com Vue Router.
  • Suporte a v-model para componentes de formulário.

Mais detalhes na documentação do Stencil.

Instalação 📦​

npm install @govbr-ds/webcomponents-vue
# ou
pnpm add @govbr-ds/webcomponents-vue
# ou
yarn add @govbr-ds/webcomponents-vue

peerDependencies​

peerDependencies são pacotes que este wrapper não instala automaticamente — o seu projeto precisa tê-los instalados.

Observe que algumas peerDependencies podem ter suas próprias peerDependencies que também precisam ser atendidas. Consulte a documentação de cada pacote para garantir que todas as dependências necessárias estejam presentes.

Por que existem: Garantem que o seu app Vue e o wrapper compartilhem a mesma instância do Vue e dos Web Components. Versões duplicadas causam erros em tempo de execução.

O que isso implica: Se as peers não estiverem instaladas ou forem incompatíveis, componentes podem não funcionar.

As peers declaradas neste pacote são:

  • vue
  • @govbr-ds/webcomponents

As versões aceitas estão em peerDependencies no package.json publicado deste pacote (também exibidas na página do npm e na política de compatibilidade). O peer @govbr-ds/webcomponents exige exatamente a mesma versão deste wrapper.

Se você seguiu o comando de instalação acima, ambas as peers já estão incluídas.

Nota importante: pnpm e tree-shaking​

Se ao consumir estes pacotes você notar que o bundler não está removendo código não utilizado (tree‑shaking), pode haver uma incompatibilidade com o layout padrão do pnpm.

Solução rápida (opcional, somente se precisar): crie um arquivo .npmrc na raiz do seu projeto com:

node-linker=hoisted

Por que isso ajuda: por padrão, o pnpm organiza as dependências em pastas isoladas com symlinks. Alguns bundlers/otimizadores se baseiam na estrutura de node_modules e no campo sideEffects para decidir o que pode ser eliminado. O layout hoisted aproxima o formato “achatado” (similar ao npm/yarn), facilitando essa análise e, em muitos casos, restaurando o tree‑shaking.

Observações:

  • Use apenas se o tree‑shaking realmente não estiver funcionando.
  • Pode aumentar o uso de disco e alterar a resolução de dependências do seu projeto.

Quickstart Vue​

Use o quickstart Vue como referência para configuração de projeto:

  • Repositório: govbr-ds-wbc-quickstart-vue
  • Servidor local: pnpm dev
  • Formulários: estado com v-model, binding manual e VeeValidate
  • Testes headless: pnpm test:e2e
  • Porta padrão: http://localhost:5173/

Uso 📚​

Configuração do template​

Ao usar @govbr-ds/webcomponents-vue, importe os componentes usados em cada SFC ou registre-os no aplicativo. Não marque br-* como isCustomElement: isso faz o compilador ignorar os proxies Vue e, com eles, a integração de v-model e eventos tipados. A opção isCustomElement serve somente para consumo direto de @govbr-ds/webcomponents, sem este wrapper.

Uso com componentes​

import { BrButton } from '@govbr-ds/webcomponents-vue'

Uso com v-model:

<script setup lang="ts">
import { BrInput } from '@govbr-ds/webcomponents-vue'
import { ref } from 'vue'

const name = ref('Lorem ipsum')
</script>

<template>
<h1>Olá {{ name }}</h1>
<BrInput name="name" placeholder="Seu nome" v-model="name" />
</template>

O v-model padrão já aponta para a propriedade correta de cada proxy:

ComponentesPropriedade/evento mapeadosValor do modeloUso
input textual e textareavalue / inputstringv-model="texto"
datas simplesvalue / inputDate | nullv-model="data"
select e radio groupvalue / changeseleçãov-model="selecao"
checkbox, radio e switchchecked / changebooleanv-model="marcado"
slider simplesvalue / inputnumberv-model="numero"
uploadfiles / changeFileList | nullv-model="arquivos"
tag selecionávelselected / changeseleçãov-model="selecionado"

Para aprender o contrato por baixo do wrapper, compare essa abordagem com o binding manual do quickstart, que usa :value/:checked e lê event.currentTarget em @input/@change.

Para datas simples, inicialize o ref com Date | null; não use a string exibida no campo como modelo. O componente só produz texto ao participar de FormData. Valores recuperados de JSON precisam ser convertidos e validados antes de voltar ao v-model.

Validação e acessibilidade com VeeValidate​

O VeeValidate mantém o modelo e as regras; o Web Component continua responsável pela interface do campo e pela Constraint Validation nativa. Replique o erro em state, em texto e em aria-invalid.

<script setup lang="ts">
import { BrButton, BrInput, BrMessage } from '@govbr-ds/webcomponents-vue'
import { useField, useForm } from 'vee-validate'

const initialValues = { email: '' }
const { handleSubmit, resetForm } = useForm({ initialValues })
const { value: email, errorMessage: emailError, handleBlur } = useField<string>('email', (value) => {
if (!value) return 'O e-mail é obrigatório.'
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) || 'Informe um e-mail válido.'
})
const submit = handleSubmit((values) => console.log(values))
const clear = () => resetForm({ values: { ...initialValues } })
</script>

<template>
<form @submit="submit" @reset="clear" novalidate>
<BrInput
name="email"
label="E-mail"
type="email"
required
v-model="email"
:state="emailError ? 'danger' : undefined"
:aria-invalid="Boolean(emailError)"
@blur="handleBlur"
/>
<BrMessage v-if="emailError" state="danger" is-feedback :message="emailError" />

<BrButton type="reset" emphasis="secondary">Limpar</BrButton>
<BrButton type="submit">Enviar</BrButton>
</form>
</template>

O reset precisa alcançar as duas fontes de estado: o botão type="reset" limpa os controles associados, inclusive upload, e resetForm() restaura o modelo, erros e estado de interação do VeeValidate.

Modelos de intervalo​

Para os componentes que trabalham com intervalo, o pacote oferece wrappers aditivos com v-model:range-value:

<script setup lang="ts">
import { ref } from 'vue'
import { BrSliderRange } from '@govbr-ds/webcomponents-vue'

const intervalo = ref({ start: 20, end: 80 })
</script>

<template>
<BrSliderRange v-model:range-value="intervalo" :min="0" :max="100" />
</template>

Os dados assíncronos continuam sob controle da aplicação. Por exemplo, use loading, options e os eventos de busca do BrSelect; o wrapper não faz requisições HTTP, cache ou autenticação.

Dependências de Build 🛠️​

Este pacote é um wrapper gerado automaticamente e depende dos artefatos produzidos pelo núcleo de Web Components.

PacoteDependência de BuildMotivo
@govbr-ds/webcomponents-vuewebcomponents:buildNecessita dos proxies gerados em src/stencil-generated; a preparação aponta esses proxies para o adaptador mantido em src/runtime.ts.

Desenvolvimento 👨‍💻​

Estrutura do projeto​

├── 📁 src
│ ├── 📁 stencil-generated
│ ├── 📄 runtime.ts
│ └── 📄 index.ts

[!WARNING] Tudo dentro de stencil-generated é sobrescrito ao gerar o build de Web Components.

src/runtime.ts não é gerado. Ele preserva o runtime oficial e impede que o marcador interno de uma prop ARIA ausente seja serializado como Symbol(). O passo de preparação reaplica automaticamente esse import após a geração dos proxies.

Scripts/Build​

nx build webcomponents
nx build vue

Nuxt 3​

O exemplo abaixo usa os Web Components diretamente no cliente, sem os proxies Vue. Nesse modo, configure vue.compilerOptions em nuxt.config.ts:

// nuxt.config.ts
export default defineNuxtConfig({
vue: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('br-'),
},
},
})

Use o plugin defineNuxtPlugin para registrar os Web Components apenas no cliente:

// plugins/govbr-ds.client.ts
import { defineCustomElements } from '@govbr-ds/webcomponents/loader'

export default defineNuxtPlugin(() => {
defineCustomElements()
})

Essa configuração trata br-* como elemento nativo e, portanto, não oferece o v-model do wrapper. Se o aplicativo registrar BrInput, BrSelect e os demais proxies Vue, remova isCustomElement e use uma estratégia de plugin compatível com o modo de renderização escolhido.

Formatos do build 📦​

A tarefa nx build vue compila o wrapper e gera a saída em dist/vue/. Abaixo estão os artefatos produzidos e quando utilizá-los.

Estrutura do dist/vue/​

dist/vue/
├── src/
│ ├── index.js ← Entrada principal (ESM)
│ ├── index.d.ts ← Tipos TypeScript
│ └── stencil-generated/
│ └── components.js ← Componentes proxy com v-model (gerados pelo Stencil)
├── package.json
└── README.md

Quando usar cada formato​

ArtefatoQuando usarObservações
src/index.jsAplicações Vue 3 (Vite, Webpack, Nuxt)Importação padrão via @govbr-ds/webcomponents-vue
src/index.d.tsAutocomplete e tipagem TypeScriptResolvido automaticamente pelo campo types do package.json

v-model e componentModels​

Os componentes de formulário suportam v-model nativamente graças à configuração componentModels do Stencil Vue output target. Isso significa que:

  • br-input, br-select, br-checkbox, br-radio e outros componentes de formulário emitem o evento correto e expõem a prop adequada para two-way binding.
  • Não é necessário configuração extra — use v-model diretamente:
<script setup lang="ts">
import { ref } from 'vue'
import { BrInput } from '@govbr-ds/webcomponents-vue'

const nome = ref('')
</script>

<template>
<BrInput v-model="nome" label="Nome" />
</template>

Documentações Complementares 📖​

Contribuindo 🤝​

Reportar Bugs/Problemas 🐛​

Abra uma issue: gitlab.com/.../issues/new

Commits 📝​

Padrões de branches e commits: gov.br/ds/wiki

Precisa de ajuda? 🆘​

Créditos 🎉​

Desenvolvido pelo SERPRO com a comunidade.

Comece aquiComponentesQuickstartsSobre o projetoRepositório GitLabVersõesDiscordGovBR-DSFAQWikiRedefinir cookies