Web Components – @govbr-ds/webcomponents
A biblioteca de Web Components do GovBR-DS é desenvolvida utilizando o Stencil, um compilador que cria Web Components (Custom Elements). O Stencil combina os melhores conceitos dos frameworks mais populares em uma ferramenta simples e eficiente. Para mais informações, visite o site oficial do Stencil.
Demonstração 🚀
Confira nossos componentes em ação:
Tecnologias 💻
Este projeto utiliza as seguintes tecnologias:
O que são Web Components? ❓
Web Components são um conjunto de tecnologias que permitem criar novos elementos HTML personalizados, reutilizáveis e encapsulados para uso em páginas e aplicativos web. Baseados em padrões da web, são suportados por todos os navegadores modernos.
O diagrama abaixo ilustra os três principais componentes dos Web Components:
- Elementos HTML personalizados: Tags HTML definidas com JavaScript, usadas como qualquer outro elemento HTML.
- Shadow DOM: Um espaço de nome encapsulado para cada elemento HTML personalizado, garantindo que estilos e scripts não interfiram no restante da página.
- Templates: Fragmentos de HTML reutilizáveis em vários elementos.
- Slots: Áreas em um elemento HTML personalizado onde templates podem ser inseridos.
Ciclo de Vida
Para entender melhor o ciclo de vida dos componentes, acesse a página https://stenciljs.com/docs/component-lifecycle.
Integração com frameworks 🔗
Integrar Web Components com frameworks pode ser desafiador em algumas situações. Para facilitar, criamos bibliotecas de integração (wrappers), que encapsulam os Web Components em bibliotecas nativas de frameworks, simplificando a integração com funcionalidades como binding.
Para mais detalhes, consulte a documentação do Stencil sobre integrações.
Vale lembrar que, em alguns casos, a integração pode não ser possível, dependendo da evolução da especificação de Web Components e do suporte dos frameworks.
Instalação 📦
Instale o pacote e os estilos base do DS como dependências de produção:
npm install @govbr-ds/webcomponents @govbr-ds/core
# ou
pnpm add @govbr-ds/webcomponents @govbr-ds/core
# ou
yarn add @govbr-ds/webcomponents @govbr-ds/core
[!NOTE] O pacote
@govbr-ds/corefornece os tokens/estilos base que os componentes utilizam.
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.
Uso 📚
Font Awesome e Fonte Rawline
Nossos componentes utilizam a Fonte Rawline e a Font Awesome padrão do DS. Ambas são essenciais para garantir a estética e funcionalidade dos componentes. Consulte a documentação no site do GovBR-DS para mais detalhes sobre como importá-las via CDN.
- Font Awesome: Biblioteca amplamente utilizada para adicionar ícones vetoriais e logotipos aos projetos, fácil de integrar e personalizar.
- Fonte Rawline: Fonte moderna e elegante, alinhada à identidade visual do Design System do GovBR-DS.
Passo-a-passo
Os Web Components GOVBR são elementos HTML regulares ou personalizados (Web Components). Em uma página HTML simples, podem ser usados como qualquer outro elemento.
<html>
<head>
<script
type="module"
src="https://cdn.jsdelivr.net/npm/@govbr-ds/webcomponents/dist/webcomponents/webcomponents.esm.js"
></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@govbr-ds/core/dist/core-tokens.min.css" />
</head>
<body>
<br-button>Clique aqui</br-button>
</body>
</html>
Eventos
Você pode escutar eventos padrão, como clique e mouseover, da mesma forma que faria com elementos HTML normais. Muitos componentes também emitem eventos personalizados, que recomendamos fortemente utilizar. Esses eventos funcionam como os eventos padrão, mas possuem nomes específicos. Consulte a documentação de cada componente para obter detalhes sobre os nomes e dados dos eventos.
<br-button>Label</br-button>
<script>
const button = document.querySelector('br-button')
button.addEventListener('click', (event) => {
console.log('Botão foi clicado', event.detail.valor)
})
</script>
Exemplos de uso
Disponibilizamos exemplos de como usar este projeto com diferentes tecnologias. Consulte o nosso grupo no GitLab e procure pelos projetos de 'Quickstart' para mais detalhes.
Desenvolvimento 👨💻
Estrutura do Projeto
├── 📁 src
├── 📁 components
├── 📁 br-component
├── 📁 sections
├── 📄 migrate.md
├── 📁 _tests
├── 📄 br-component.e2e.ts
├── 📄 br-component.spec.tsx
├── 📄 readme.md
├── 📄 br-component.scss
├── 📄 br-component.tsx
├── 📁 pages
├── 📁 components
├── 📁 br-component
├── 📄 index.js
├── 📄 exemplo.html
├── 📁 scripts
├── 📄 index.html
├── 📁 value-accessors
├── 📄 stencil.config.ts
├── ...
- src: Contém o código-fonte do projeto.
- components: Diretório com os componentes Web criados com Stencil. Cada componente possui sua própria pasta.
- br-component: Pasta específica para o componente
br-component.- sections: Contém arquivos markdown para inclusão no site.
- migrate.md: Explica como migrar o componente da versão anterior para a nova.
- _tests: Contém os arquivos de teste.
- br-component.e2e.ts: Testes end-to-end (E2E) do componente.
- br-component.spec.tsx: Testes unitários (Unit) do componente.
- br-component.tsx: Arquivo principal do componente, com lógica e estrutura.
- br-component.scss: Arquivo de estilo do componente.
- readme.md: Documentação gerada automaticamente durante o
build.
- sections: Contém arquivos markdown para inclusão no site.
- br-component: Pasta específica para o componente
- pages: Contém exemplos dos componentes Web criados com Stencil.
- components: Diretório com exemplos dos componentes.
- br-component: Pasta específica para o componente
br-component.- index.js: Arquivo para executar ações nos exemplos, como escutar eventos.
- exemplo.html: Arquivo com o código de cada exemplo.
- br-component: Pasta específica para o componente
- scripts: Scripts usados no ambiente de desenvolvimento.
- components: Diretório com exemplos dos componentes.
- value-accessors: Configurações para 2-way binding em Angular e Vue.
- index.html: Página inicial do servidor de desenvolvimento.
- components: Diretório com os componentes Web criados com Stencil. Cada componente possui sua própria pasta.
- stencil.config.ts: Arquivo principal de configuração do projeto Stencil, onde são definidas opções como saída do build, plugins e scripts globais.
Scripts Disponíveis
No arquivo package.json e project.json, você encontrará diversos scripts úteis. Abaixo está uma lista com a descrição de cada um deles:
nx start webcomponents: Inicia o site localmente para desenvolvimento.nx build webcomponents: Realiza a compilação do projeto para produção.nx test:unit webcomponents: Executa os testes unitários.nx lint:tsx webcomponents: Realiza a análise estática nos arquivos TypeScript.nx lint:md webcomponents: Realiza a análise estática nos arquivos markdown.nx lint:styles webcomponents: Realiza a análise estática nos arquivos de estilo.
Gerenciar baseline de tamanho:
# Da raiz do monorepo:
pnpm run baseline:update:webcomponents # Atualizar baseline
pnpm run baseline:compare:webcomponents # Comparar com baseline atual
Build
Ao gerar o build deste projeto Stencil, são automaticamente criados:
- O arquivo
readme.mddentro da pasta de cada componente. - Documentações dos componentes na pasta
apps/site/docs/stencil-generated-docs, que podem ser utilizadas e versionadas pelo site.
nx build webcomponents
Testes
Nossa estratégia de testes é dividida em duas abordagens principais: testes unitários e testes end-to-end (E2E).
Testes Unitários (*.spec.tsx)
Os testes unitários são ideais para validar a lógica interna dos componentes de forma isolada e eficiente. Utilizamos o método newSpecPage() para verificar:
- Estado inicial: comportamento do componente sem propriedades.
- Propriedades: valores válidos, inválidos e alterações em tempo de execução.
- Classes CSS: presença e ausência de classes condicionais.
- Slots: renderização correta do conteúdo.
- Lógica interna: métodos, cálculos e transformações.
- Validações básicas: required, minLength, maxValue, entre outras.
import { newSpecPage } from '@stencil/core/testing'
import { BrComponent } from '../component'
it('deve inicializar com o estado padrão', async () => {
const page = await newSpecPage({
components: [BrComponent],
html: /*html*/ `<br-component></br-component>`,
})
expect(page.root).toEqualHtml(`<br-component>...</br-component>`)
})
Testes E2E (*.e2e.ts)
Os testes E2E são realizados em um navegador real utilizando o método newE2EPage(). Embora sejam mais lentos, são fundamentais para validar:
- Eventos do componente: clique, blur, change, entre outros.
- Interações do usuário: drag-drop, digitação, atalhos.
- Integrações DOM: forms, validação nativa, atributos aria-*.
- Estilos visuais: dimensões, cores, transições.
- Shadow DOM: slots, parts, estilos encapsulados.
import { newE2EPage } from '@stencil/core/testing'
describe('br-component', () => {
it('deve renderizar', async () => {
const page = await newE2EPage()
await page.setContent(/*html*/ `<br-component></br-component>`)
const element = await page.find('br-component')
expect(element).toHaveClass('hydrated')
})
it('deve ter shadow root', async () => {
const page = await newE2EPage()
await page.setContent(/*html*/ `<br-component-component></br-component-component>`)
const element = await page.find('br-component')
expect(element.shadowRoot).not.toBeNull()
})
})
Para mais informações sobre testes no Stencil, consulte a documentação oficial.
Formatos do build 📦
A tarefa nx build webcomponents lê as definições de saída em stencil.config.ts e gera múltiplos formatos dentro de dist/webcomponents/dist. Cada pasta/arquivo atende um cenário específico de consumo da biblioteca. O resumo abaixo ajuda a identificar qual artefato utilizar em cada contexto.
Visão rápida
| Pasta/arquivo | Origem no build | Quando usar | Observações |
|---|---|---|---|
cjs/ | outputTargets: { type: 'dist' } | Bundlers ou runtimes que ainda resolvem CommonJS (require) | Referenciado pelo campo main do package.json e inclui loader.cjs.js |
esm/ | outputTargets: { type: 'dist' } | Bundlers modernos/ESBuild/Vite/Rollup com suporte a ESM e tree-shaking | Referenciado pelo campo module do package.json |
components/ | outputTargets: { type: 'dist-custom-elements' } | Importações diretas de componentes individuais, geração de wrappers Angular/React/Vue | Gera .js + .d.ts por componente |
collection/ | outputTargets: { type: 'dist' } (manifest Stencil) | Projetos Stencil que desejam consumir os componentes como dependência | Descrito pelos campos collection e collection:main do package.json |
hydrate/ | outputTargets: { type: 'dist-hydrate-script' } | SSR/pré-renderização em Node, integrações como React SSR target | Exporta scripts CommonJS/ESM para @govbr-ds/webcomponents/dist/hydrate |
loader/ | outputTargets: { type: 'dist' } | Registro manual dos componentes em apps vanilla, integrações legadas | Disponibiliza defineCustomElements() em múltiplos formatos |
webcomponents/ | outputTargets: { type: 'dist' } | Consumo via CDN (ex.: <script type="module" ...>) | Contém webcomponents.esm.js e os chunks dinâmicos p-*.entry.js; os estilos vêm de @govbr-ds/core |
types/ | generateTypeDeclarations: true (custom elements + d.ts globais) | Autocomplete/TypeScript/IDE hints | Referenciado por types em package.json |
custom-elements.json e webcomponents.html-custom-data.json | Derivados do compilador | IntelliSense e validação em IDEs/editores | VS Code utiliza via html.customData |
index.js / index.cjs.js | Entradas principais do pacote | Re-exportam os módulos esm/cjs e definem side-effects | Apontados por module/main |
cjs/ – bundles CommonJS
- Contém
index.cjs.js,webcomponents.cjs.jse um arquivo*.entry.jspor componente, acompanhados dos source maps (.map). - É resolvido sempre que o consumidor faz
require('@govbr-ds/webcomponents')ou quando o bundler privilegia o campomaindefinido em package.json. - Use este formato em toolchains legadas (Node 14/16, Webpack < 4, Jest sem suporte a ESM) ou quando precisar depurar módulos CommonJS. Inclui também
loader.cjs.js, permitindo registrar os elementos manualmente comrequire('@govbr-ds/webcomponents/dist/loader').
esm/ – bundles ES Modules
- Equivalente modular do
cjs/, com chunks otimizados (p-*.entry.js) ewebcomponents.esm.js. - É o alvo do campo
moduledo pacote e atende bundlers modernos (Vite, Webpack 5+, Rollup, ESBuild) que fazem tree-shaking. Como os chunks mantêm imports explícitos, apenas o necessário é incluído no bundle final. - Prefira esta saída quando o projeto já executa em módulos nativos ou quando precisa de melhor performance em builds SPA/MPA modernos.
components/ – dist-custom-elements
- Resultado do
outputTargets: { type: 'dist-custom-elements', customElementsExportBehavior: 'single-export-module' }definido em stencil.config.ts. - Cada componente possui um arquivo isolado (
br-button.js) e o respectivo.d.ts, permitindo importar diretamenteimport { BrButton } from '@govbr-ds/webcomponents/dist/components/br-button'sem puxar o bundle completo. - Esta pasta também alimenta os geradores Angular/React/Vue configurados no mesmo arquivo (
customElementsDiraponta paradist/components). Use-a para criar wrappers customizados ou testar componentes isoladamente em Storybook.
collection/ – manifest Stencil
- Inclui
collection-manifest.json, cópias de assets/páginas e os proxies de acesso (index.js). - Necessário apenas para quem desenvolve outra biblioteca Stencil e deseja usar
@govbr-ds/webcomponentscomo dependência, preservando metadados como slots, eventos e estilos. - Os campos
collectionecollection:mainno package.json apontam para esses arquivos para que o compilador Stencil dos consumidores encontre as definições.
hydrate/ – script para SSR/pré-render
- Produzido pelo target
dist-hydrate-scripte exportado como módulo CommonJS/ESM (index.js,index.mjs). - Permite renderizar componentes em ambientes sem DOM (Node.js) e hidratar o HTML no cliente. O React SSR output target e a configuração de Vue (
hydrateModule: '@govbr-ds/webcomponents/dist/hydrate') dependem desta pasta. - Utilize quando precisar pré-renderizar páginas (Next.js, Astro, custom SSR) ou ao gerar imagens/relatórios estáticos com os componentes já resolvidos.
loader/ – helpers para registro manual
- Disponibiliza
defineCustomElements()eapplyPolyfills()em diferentes formatos (index.js,index.cjs.js,index.es2017.js,cdn.js). - Ideal para projetos vanilla ou quando o bundle principal não deve executar automaticamente o
defineCustomElements. Você importa apenas o loader, registra os componentes no momento oportuno e mantém controle fino sobre o Custom Elements Registry. - Use
cdn.jsem páginas HTML estáticas (por exemplo,<script src="https://cdn.jsdelivr.net/npm/@govbr-ds/webcomponents/dist/loader/cdn.js"></script>) quando precisa apenas do registro.
webcomponents/ – pacote pronto para CDN
- É a forma mais simples de consumo:
webcomponents.esm.js+ chunksp-*.entry.js, prontos para serem servidos via CDN. - Recomendada para páginas estáticas, protótipos, Storybook do Design System ou integrações que não passam por bundlers. Lembre-se de importar os estilos de
@govbr-ds/core(tokens) separadamente. - Inclui chunks nomeados resolvidos dinamicamente pelo loader gerado pelo Stencil, permitindo lazy loading automático.
types/ – declarações TypeScript
- Resultado da opção
generateTypeDeclarations: trueda saídadist-custom-elements. - Contém
components.d.tscom todas as interfaces de propriedades/eventos e uma pastacomponents/com os tipos específicos. O campotypesdopackage.jsonaponta paradist/types/index.d.ts. - Necessário para projetos TypeScript, IDEs e também para os wrappers Angular/React/Vue, que reexportam esses tipos.
Metadados auxiliares
custom-elements.json: arquivo padrão da especificação Custom Elements Manifest. Importante para ferramentas de documentação e IDEs.webcomponents.html-custom-data.json: arquivo usado pelo VS Code viahtml.customDatapara habilitar autocomplete e validação nos editores.index.js/index.cjs.js: reexportam os bundles ESM/CJS e expõemdefineCustomElements()/setNonce()gerados pelo Stencil; raramente precisam ser importados diretamente.- Documentação Markdown: gerada automaticamente em
apps/site/docs/stencil-generated-docsviaoutputTargets.docs-custom, mas não é distribuída dentro dedist/webcomponents.
Como escolher o formato correto
- Aplicações modernas com bundler: instale o pacote e deixe seu bundler resolver o campo
module→ carregaráesm/automaticamente. - SSR ou pré-render: combine
esm/no cliente comhydrate/no servidor para renderização isomórfica. - Integrações framework-nativas: use os pacotes
@govbr-ds/angular|react|vue, gerados a partir decomponents/e com tipos emtypes/. - Páginas estáticas/CDN: carregue diretamente os arquivos em
webcomponents/e use oloader/se precisar controlar o registro manualmente. - Toolchains legadas: force o campo
maine consumacjs/para manter compatibilidade com CommonJS.
Manter estes contextos claros evita duplicidade de código, falta de tree-shaking ou registros repetidos de Custom Elements.
VS Code IntelliSense
Durante o desenvolvimento de nossos Web Components, utilizamos custom elements. O VS Code, por padrão, não reconhece esses componentes, o que impede sugestões inteligentes no autocomplete. Para resolver isso, geramos um arquivo com as definições dos componentes, disponibilizado junto ao pacote npm.
Para importar no seu VS Code, adicione o seguinte campo, ajustando o caminho para o local onde o node_modules está armazenado no seu projeto:
{
"html.customData": ["./node_modules/@govbr-ds/webcomponents/dist/webcomponents/webcomponents.html-custom-data.json"]
}
Documentações Complementares 📖
Consulte a seção sobre Web Components na nossa Wiki para obter mais informações sobre este projeto.
Para mais detalhes sobre a especificação de Web Components, recomendamos a consulta ao MDN.
Contribuindo 🤝
Antes de abrir um Merge Request, considere as seguintes orientações:
- Este é um projeto open-source, e contribuições são sempre bem-vindas.
- Para facilitar a aprovação da sua contribuição, utilize um título claro e explicativo no MR e siga os padrões descritos em nossa wiki.
- Deseja contribuir? Consulte o nosso guia como contribuir.
Reportar Bugs/Problemas ou Sugestões 🐛
Caso encontre problemas ou tenha sugestões de melhorias, abra uma issue. Utilize o modelo apropriado e forneça o máximo de detalhes possível.
Nos comprometemos a responder a todas as issues.
Commits 📝
Este projeto segue um padrão específico para branches e commits. Consulte a documentação em nossa wiki para entender mais sobre esses padrões.
Precisa de ajuda? 🆘
Por favor, não crie issues para dúvidas gerais.
Utilize os canais abaixo para esclarecer suas dúvidas:
- Site do GovBR-DS http://gov.br/ds
- Web Components https://gov.br/ds/webcomponents
- Canal no Discord https://discord.gg/U5GwPfqhUP
Créditos 🎉
Os Web Components do GovBR-DS foram desenvolvidos pelo SERPRO em parceria com a comunidade.
Nota sobre pnpm e tree-shaking
Em alguns cenários, para que o tree‑shaking funcione corretamente (especialmente em bundlers que dependem da estrutura de node_modules e da resolução de sideEffects), pode ser necessário configurar o pnpm para usar o layout de dependências "hoisted".
Crie um arquivo .npmrc na raiz do seu projeto (caso ainda não exista) com:
node-linker=hoisted
Por quê: o layout padrão do pnpm usa pastas isoladas com symlinks, o que pode confundir determinadas ferramentas de build/otimização ao analisar limites de módulos e sideEffects. O node-linker=hoisted aproxima o layout do de npm/yarn (flat/hoisted), facilitando a análise estática e, consequentemente, o tree‑shaking. Use essa opção apenas se perceber problemas de eliminação de código morto; ela pode aumentar o uso de disco e alterar a resolução de dependências.