@govbr-ds/webcomponents
v2.0.0
Published
Biblioteca de Web Components baseado no GovBR-DS
Readme
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.
Compatibilidade de Navegadores 🌐
| Navegador | Versão mínima | Observações | | ---------------- | ------------- | --------------------------------- | | Chrome | 79+ | Suporte completo a Web Components | | Edge | 79+ | Baseado em Chromium | | Firefox | 63+ | Suporte completo | | Safari | 14+ | Requer macOS 11+ ou iOS 14+ | | Opera | 66+ | Baseado em Chromium | | Samsung Internet | 12+ | Baseado em Chromium |
[!NOTE] Internet Explorer não é suportado. O target de compilação TypeScript é
es2020.
Instalação 📦
Instale o pacote e os estilos base do Design System como dependências de produção:
npm install @govbr-ds/core @govbr-ds/webcomponents
# ou
yarn add @govbr-ds/core @govbr-ds/webcomponents
# ou
pnpm add @govbr-ds/core @govbr-ds/webcomponentspeerDependencies
peerDependencies são pacotes que este pacote não instala automaticamente — o seu projeto precisa tê-los instalados.
Por que existem: O pacote depende de bibliotecas externas para posicionamento de elementos flutuantes, estilos e datas. Declará-las como peers garante que o seu app e o pacote usem a mesma versão dessas bibliotecas, evitando conflitos.
O que isso implica: Se as peers não estiverem instaladas ou forem incompatíveis, componentes como br-datetime-picker e br-tooltip podem não funcionar.
As peers declaradas neste pacote são:
| Pacote | Versão compatível |
| ------------------ | ----------------- |
| @govbr-ds/core | >=3.6.0 <4.0.0 |
| @floating-ui/dom | >=1.7.6 |
| date-fns | >=4.1.0 |
| iconify-icon | 3.0.2 |
npm install @floating-ui/dom date-fns iconify-icon
# ou
pnpm add @floating-ui/dom date-fns iconify-iconNota 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=hoistedPor 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 📚
Ícones (Iconify)
O componente br-icon utiliza a biblioteca Iconify para renderização de ícones. Por padrão, os dados dos ícones são carregados sob demanda via rede a partir da API CDN do Iconify (api.iconify.design).
Requisitos de rede e CSP
| Recurso | Domínio | Finalidade |
| -------------------- | ----------------------------------------------------------- | ----------------------------- |
| API de ícones | https://api.iconify.design | Carregamento de dados SVG |
| Script CDN (se usar) | https://cdn.jsdelivr.net ou https://code.iconify.design | Carregamento do web component |
Se o seu projeto utiliza Content Security Policy (CSP), adicione os domínios acima às diretivas adequadas:
Content-Security-Policy:
connect-src 'self' https://api.iconify.design;
script-src 'self' https://cdn.jsdelivr.net;Limitações
Sem internet, sem ícones: se o navegador não conseguir acessar
api.iconify.design, os ícones não serão renderizados na primeira visita. Após o primeiro carregamento, o Iconify faz cache emlocalStorage/sessionStorage.Impacto no LCP/CLS: como os ícones são carregados assincronamente, pode haver um pequeno atraso na renderização. Para mitigar, defina dimensões explícitas via CSS:
iconify-icon { display: inline-block; width: 1em; height: 1em; }
Alternativa: ícones pré-carregados (offline / CSP restritivo)
Para ambientes sem acesso à internet ou com CSP restritivo que bloqueie connect-src externo, pré-carregue os ícones necessários com as funções addIcon() ou addCollection():
import { addIcon } from 'iconify-icon'
// Registrar ícone individual (não depende de rede)
addIcon('fa-solid:check', {
body: '<path fill="currentColor" d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7l233.4-233.3c12.5-12.5 32.8-12.5 45.3 0z"/>',
width: 448,
height: 512,
})Para coleções inteiras:
import { addCollection } from 'iconify-icon'
addCollection({
prefix: 'custom',
icons: {
home: {
body: '<path d="M10 20v-6h4v6h5v-8h3L12 3L2 12h3v8h5z" fill="currentColor"/>',
},
},
width: 24,
height: 24,
})Alternativa: API Iconify auto-hospedada
Para organizações que necessitam de controle total, é possível hospedar a API Iconify internamente e redirecionar os componentes:
import { addAPIProvider } from 'iconify-icon'
addAPIProvider('', {
resources: ['https://iconify.sua-organizacao.gov.br'],
})Para mais informações, consulte a documentação oficial do Iconify.
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>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)
})
</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 👨💻
Scripts Disponíveis
No arquivo package.json e project.json, você encontrará diversos scripts úteis para o desenvolvimento e manutenção dos Web Components.
Tarefas de Build
O pacote possui diferentes níveis de build gerenciados pelo Nx. Abaixo estão os detalhes de cada tarefa:
| Tarefa | Descrição | O que gera |
| :--- | :--- | :--- |
| build | Tarefa principal de build para distribuição completa. | Core (dist), Wrappers (Angular/React/Vue), SSR (hydrate) e metadados (cem). |
| build:dist | Build focado na distribuição "vanilla" (puro Custom Elements). | Core (dist) e metadados (cem). Não inclui SSR/Hydrate. |
| build:all | Build completo de todo o ecossistema do pacote. | Tudo da tarefa build + Site/Playground (www) + Documentação técnica auto-gerada. |
| build:hydrate | Build específico para suporte a Server-Side Rendering (SSR). | App de hidratação em dist/webcomponents/dist/hydrate. |
| build:www | Build do playground/site de testes interno. | Pasta www com os componentes carregados para visualização local. |
| build:docs | Build de documentação técnica automática. | Gera/atualiza os arquivos README.md dentro da pasta de cada componente. |
Outros Scripts
nx start webcomponents: Inicia o site localmente para desenvolvimento.nx run webcomponents:tests: Executa os testes E2E em browser mode.nx run webcomponents:lint:biome: Realiza a análise estática com Biome.nx run webcomponents:lint:md: Realiza a análise estática nos arquivos Markdown.pnpm test:component <arquivo>: Executa somente um teste E2E.
Gerenciar baseline de tamanho:
# Da raiz do monorepo:
pnpm baseline:update
pnpm baseline:compareBuild e Documentação Autogerada
Ao gerar o build (ou build:docs) deste projeto Stencil, são automaticamente criados ou atualizados:
- O arquivo
readme.mddentro da pasta de cada componente (contendo especificações de props, eventos, slots, etc). - Documentações dos componentes na pasta
apps/site/docs/stencil-generated-docs, que são consumidas pelo site oficial.
nx build webcomponentsTestes
Nossa estratégia de testes utiliza testes end-to-end (E2E) executados em navegador.
Testes E2E (*.e2e.tsx)
Os testes E2E rodam em browser mode com @stencil/vitest, usando render() e
userEvent. Cenários de viewport, regressão visual ou consultas profundas em
Shadow DOM usam a fachada tipada createBrowserTestFixture().
Esse tipo de teste é fundamental 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 { h } from '@stencil/core'
import { describe, expect, it, render } from '@stencil/vitest'
describe('br-component', () => {
it('deve renderizar', async () => {
const { root } = await render(<br-component></br-component>)
expect(root).not.toBeNull()
})
it('deve ter shadow root', async () => {
const { root } = await render(<br-component></br-component>)
expect(root).toHaveShadowRoot()
})
})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/componentsdentro do pacote publicado). 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=hoistedPor 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.
