@schenkerjon/ng-govbr-tw
v0.1.0
Published
Angular components following Gov.br Design System, styled with Tailwind CSS 3
Maintainers
Readme
@schenkerjon/ng-govbr-tw
Biblioteca Angular de componentes baseados no Design System do Governo Federal (GovBR DS), estilizados com Tailwind CSS 3. Componentes standalone, acessíveis e prontos para produção.
Compatível com Angular 17, 18 e 19.
Instalação
npm install @schenkerjon/ng-govbr-twConfiguração automática (recomendado)
ng add @schenkerjon/ng-govbr-twO schematic configura automaticamente:
- Preset Tailwind no
tailwind.config.js - Fontes Rawline e Font Awesome no
index.html - Import do CSS no
styles.css
Configuração manual
- Adicione o preset ao
tailwind.config.js:
const govbrPreset = require('@schenkerjon/ng-govbr-tw/tailwind.preset');
module.exports = {
presets: [govbrPreset],
content: [
"./src/**/*.{html,ts}",
"./node_modules/@schenkerjon/ng-govbr-tw/**/*.{mjs,js}"
],
};- Adicione as fontes no
index.html:
<link href="https://fonts.googleapis.com/css2?family=Raleway:wght@100;300;400;500;600;700;900&display=swap" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" rel="stylesheet" />- Importe o CSS base:
/* styles.css */
@import '@schenkerjon/ng-govbr-tw/src/lib/styles/govbr-tw.css';Uso
Todos os componentes são standalone — importe diretamente:
import { BrButtonComponent, BrInputComponent } from '@schenkerjon/ng-govbr-tw';
@Component({
standalone: true,
imports: [BrButtonComponent, BrInputComponent],
})Sumário de Componentes
| Categoria | Componentes |
|-----------|-------------|
| Layout | br-layout, br-header, br-footer, br-menu, br-menu-item, br-sidebar |
| Navegação | br-menu-bar, br-mega-menu, br-breadcrumb, br-tab, br-pagination |
| Formulários | br-input, br-select, br-checkbox, br-radio-group, br-textarea, br-datepicker, br-timepicker, br-datetimepicker |
| Botões | br-button, br-magic-button |
| Dados | br-table, br-card, br-item, br-list, br-badge |
| Feedback | br-message, br-modal, br-loading, br-tooltip |
| Utilitários | br-accordion, br-wizard, br-cookiebar |
Layout
br-layout
Estrutura principal da aplicação. Organiza header, menu lateral (push), conteúdo e footer.
<br-layout>
<br-header
systemTitle="Meu Sistema"
logoSrc="assets/logo.png"
(menuToggle)="menuOpen = $event"
></br-header>
<br-menu [open]="menuOpen" (openChange)="menuOpen = $event">
<br-menu-item label="Início" icon="house" route="/"></br-menu-item>
<br-menu-item label="Documentos" icon="file" route="/docs"></br-menu-item>
</br-menu>
<div>Conteúdo da página</div>
<br-footer logoSrc="assets/logo.png"></br-footer>
</br-layout>br-header
Header GovBR DS com duas linhas: logo/ações (topo) e título/busca (inferior).
<br-header
systemTitle="Nome do Sistema"
systemSubtitle="Órgão responsável"
logoSrc="assets/gov-logo.png"
logoHref="/"
signature="gov.br"
variant="primary"
density="medium"
[sticky]="true"
menuMode="sidebar"
[showSearch]="true"
[showLogin]="true"
[hasLinks]="true"
[hasFunctions]="true"
userName="João Silva"
userRole="Administrador"
avatarSrc="assets/avatar.jpg"
(menuToggle)="menuOpen = $event"
(searchSubmit)="onSearch($event)"
(signIn)="onLogin()"
(logout)="onLogout()"
>
<!-- Links de acesso rápido (dropdown ⋮) -->
<a header-links href="/acessibilidade" class="block px-4 py-2 text-sm hover:bg-gray-50">
Acessibilidade
</a>
<a header-links href="/mapa-do-site" class="block px-4 py-2 text-sm hover:bg-gray-50">
Mapa do site
</a>
<!-- Funcionalidades do sistema (dropdown ⊞) -->
<a header-functions href="/notificacoes" class="block px-4 py-2 text-sm hover:bg-gray-50">
Notificações
</a>
<!-- Menu do avatar -->
<a avatar-menu href="/perfil" class="block px-4 py-2 text-sm hover:bg-gray-50">
Meu perfil
</a>
</br-header>| Input | Tipo | Padrão | Descrição |
|-------|------|--------|-----------|
| systemTitle | string | '' | Título do sistema |
| systemSubtitle | string | — | Subtítulo (órgão, departamento) |
| logoSrc | string | '' | URL do logo |
| logoHref | string | — | Link do logo |
| signature | string | — | Assinatura (ex: "gov.br") |
| variant | 'primary' \| 'white' | 'primary' | Tema de cores |
| density | 'small' \| 'medium' \| 'large' | 'medium' | Tamanho do header |
| sticky | boolean | false | Header fixo no topo |
| menuMode | 'sidebar' \| 'mega' \| 'none' | 'sidebar' | Tipo de menu |
| showSearch | boolean | true | Exibir busca |
| showContrast | boolean | false | Exibir botão de alto contraste |
| contrastActive | boolean | false | Alto contraste ativo |
| showLogin | boolean | true | Exibir botão entrar |
| hasLinks | boolean | false | Exibir dropdown de links rápidos |
| hasFunctions | boolean | false | Exibir dropdown de funcionalidades |
| userName | string | — | Nome do usuário logado |
| userRole | string | — | Cargo/papel do usuário |
| avatarSrc | string | — | URL da foto do avatar |
| Output | Tipo | Descrição |
|--------|------|-----------|
| menuToggle | boolean | Menu abriu/fechou |
| searchSubmit | string | Texto pesquisado |
| signIn | void | Clicou em "Entrar" |
| logout | void | Clicou em "Sair" |
| contrastChange | boolean | Alto contraste alterado |
Slots de conteúdo: [header-links], [header-functions], [avatar-menu]
br-menu
Menu lateral push — quando aberto, empurra o conteúdo para o lado.
<br-menu [open]="menuOpen" (openChange)="menuOpen = $event" variant="white" width="default">
<br-menu-item label="Início" icon="house" route="/" [exact]="true"></br-menu-item>
<br-menu-item label="Usuários" icon="users" route="/usuarios"></br-menu-item>
<!-- Item com submenu -->
<br-menu-item label="Configurações" icon="gear" [hasChildren]="true" [expanded]="configExpanded" (expandedChange)="configExpanded = $event">
<br-menu-item label="Geral" route="/config/geral"></br-menu-item>
<br-menu-item label="Segurança" route="/config/seguranca"></br-menu-item>
</br-menu-item>
<!-- Footer do menu -->
<div menu-footer>
<span class="text-xs text-gray-500">v1.0.0</span>
</div>
</br-menu>| Input | Tipo | Padrão | Descrição |
|-------|------|--------|-----------|
| open | boolean | true | Menu aberto/fechado |
| variant | 'white' \| 'light' | 'white' | Cor de fundo |
| width | 'narrow' \| 'default' \| 'wide' | 'default' | Largura (60/64/72) |
| hasFooter | boolean | false | Exibir área de footer |
| ariaLabel | string | 'Menu principal' | Label de acessibilidade |
br-menu-item
| Input | Tipo | Padrão | Descrição |
|-------|------|--------|-----------|
| route | string \| unknown[] | — | Rota Angular (routerLink) |
| label | string | '' | Texto do item |
| icon | string | — | Nome Font Awesome (sem fa-) |
| badge | string \| number | — | Badge/contador vermelho |
| exact | boolean | false | routerLinkActive exato |
| hasChildren | boolean | false | Tem submenu |
| expanded | boolean | false | Submenu expandido |
br-footer
<br-footer logoSrc="assets/logo-footer.png">
<div class="text-sm text-gray-600">© 2024 Governo Federal</div>
</br-footer>Navegação
br-menu-bar
Barra de navegação horizontal abaixo do header.
<br-menu-bar variant="primary">
<br-menu-bar-item label="Início" icon="house" route="/"></br-menu-bar-item>
<br-menu-bar-item label="Serviços" icon="grid" [hasSubmenu]="true">
<br-menu-bar-sub-item label="Consulta" route="/servicos/consulta"></br-menu-bar-sub-item>
<br-menu-bar-sub-item label="Solicitação" route="/servicos/solicitacao"></br-menu-bar-sub-item>
</br-menu-bar-item>
</br-menu-bar>| Input | Tipo | Padrão |
|-------|------|--------|
| variant | 'primary' \| 'dark' \| 'white' | 'primary' |
br-mega-menu
Menu mega com colunas e categorias.
<br-mega-menu variant="primary" [activePanel]="activePanel" (activePanelChange)="activePanel = $event">
<br-mega-menu-trigger label="Serviços" panelId="servicos" icon="grid"></br-mega-menu-trigger>
<br-mega-menu-trigger label="Institucional" panelId="institucional"></br-mega-menu-trigger>
<br-mega-menu-panel panelId="servicos" [isActive]="activePanel === 'servicos'">
<br-mega-menu-column title="Cidadão">
<br-mega-menu-link label="CPF" route="/servicos/cpf" icon="id-card"></br-mega-menu-link>
<br-mega-menu-link label="Passaporte" route="/servicos/passaporte"></br-mega-menu-link>
</br-mega-menu-column>
</br-mega-menu-panel>
</br-mega-menu>br-breadcrumb
<br-breadcrumb [items]="breadcrumbs" [showHome]="true" homeRoute="/"></br-breadcrumb>import { BrBreadcrumbItem } from '@schenkerjon/ng-govbr-tw';
breadcrumbs: BrBreadcrumbItem[] = [
{ label: 'Serviços', route: '/servicos' },
{ label: 'Consulta', route: '/servicos/consulta' },
{ label: 'Resultado' },
];br-tab
<br-tab density="medium" [activeIndex]="0" (activeIndexChange)="onTabChange($event)">
<br-tab-panel label="Dados" icon="file">
Conteúdo da aba Dados
</br-tab-panel>
<br-tab-panel label="Histórico" icon="clock" [counter]="5">
Conteúdo da aba Histórico
</br-tab-panel>
<br-tab-panel label="Desativada" [disabled]="true">
...
</br-tab-panel>
</br-tab>| Input (br-tab) | Tipo | Padrão |
|-------|------|--------|
| density | 'small' \| 'medium' \| 'large' | 'medium' |
| activeIndex | number | 0 |
| inverted | boolean | false |
| Input (br-tab-panel) | Tipo | Padrão |
|-------|------|--------|
| label | string | '' |
| icon | string | — |
| counter | number | — |
| disabled | boolean | false |
br-pagination
<br-pagination
[page]="currentPage"
[totalPages]="20"
[maxVisible]="5"
[showFirstLast]="true"
density="medium"
(pageChange)="currentPage = $event"
></br-pagination>| Input | Tipo | Padrão |
|-------|------|--------|
| page | number | 1 |
| totalPages | number | 1 |
| maxVisible | number | 5 |
| showFirstLast | boolean | false |
| density | 'small' \| 'medium' \| 'large' | 'medium' |
Formulários
Todos os componentes de formulário implementam ControlValueAccessor — funcionam com [(ngModel)] e formControl.
br-input
<br-input
label="Nome completo"
placeholder="Digite seu nome"
[(ngModel)]="nome"
[required]="true"
icon="user"
density="medium"
helperText="Informe seu nome completo"
></br-input>
<!-- Com validação -->
<br-input label="E-mail" type="email" [(ngModel)]="email" error="E-mail inválido"></br-input>
<!-- Busca -->
<br-input type="search" placeholder="Pesquisar..." [(ngModel)]="busca" (searchSubmit)="pesquisar($event)"></br-input>
<!-- Arquivo -->
<br-input label="Documento" type="file" (fileSelected)="onFile($event)"></br-input>| Input | Tipo | Padrão | Descrição |
|-------|------|--------|-----------|
| label | string | — | Rótulo do campo |
| type | string | 'text' | text, email, password, number, search, file, select, textarea |
| placeholder | string | '' | Placeholder |
| required | boolean | false | Obrigatório |
| error | string | — | Mensagem de erro |
| successMessage | string | — | Mensagem de sucesso |
| warningMessage | string | — | Mensagem de aviso |
| helperText | string | — | Texto auxiliar |
| icon | string | — | Ícone Font Awesome |
| iconRight | boolean | false | Ícone à direita |
| density | 'small' \| 'medium' \| 'large' | 'medium' | Tamanho |
| highlight | boolean | false | Destaque visual |
| maxLength | number | — | Máximo de caracteres |
br-select
<br-select
label="Estado"
placeholder="Selecione o estado"
[(ngModel)]="estado"
[options]="estados"
[searchable]="true"
[required]="true"
></br-select>
<!-- Seleção múltipla -->
<br-select label="Categorias" [(ngModel)]="categorias" [options]="categoriasOpts" [multiple]="true"></br-select>import { BrSelectOption } from '@schenkerjon/ng-govbr-tw';
estados: BrSelectOption[] = [
{ label: 'São Paulo', value: 'SP' },
{ label: 'Rio de Janeiro', value: 'RJ' },
{ label: 'Minas Gerais', value: 'MG' },
];| Input | Tipo | Padrão |
|-------|------|--------|
| label | string | — |
| placeholder | string | 'Selecione' |
| options | BrSelectOption[] | [] |
| required | boolean | false |
| error | string | — |
| multiple | boolean | false |
| searchable | boolean | false |
| density | 'small' \| 'medium' \| 'large' | 'medium' |
br-checkbox
<br-checkbox label="Aceito os termos de uso" [(ngModel)]="aceitoTermos"></br-checkbox>
<br-checkbox label="Selecionar todos" [indeterminate]="algumSelecionado" [(ngModel)]="todosSelecionados"></br-checkbox>| Input | Tipo | Padrão |
|-------|------|--------|
| label | string | — |
| indeterminate | boolean | false |
| error | string | — |
| size | 'default' \| 'small' | 'default' |
| state | 'default' \| 'valid' \| 'invalid' | 'default' |
br-radio-group
<br-radio-group
legend="Tipo de pessoa"
[(ngModel)]="tipoPessoa"
[options]="tipoPessoaOpts"
[inline]="true"
></br-radio-group>import { BrRadioOption } from '@schenkerjon/ng-govbr-tw';
tipoPessoaOpts: BrRadioOption[] = [
{ label: 'Pessoa Física', value: 'PF' },
{ label: 'Pessoa Jurídica', value: 'PJ' },
];| Input | Tipo | Padrão |
|-------|------|--------|
| legend | string | — |
| options | BrRadioOption[] | [] |
| required | boolean | false |
| error | string | — |
| inline | boolean | false |
| size | 'default' \| 'small' | 'default' |
br-textarea
<br-textarea
label="Observações"
placeholder="Digite suas observações..."
[(ngModel)]="observacoes"
[rows]="5"
[maxLength]="500"
helperText="Máximo de 500 caracteres"
resizable="vertical"
></br-textarea>| Input | Tipo | Padrão |
|-------|------|--------|
| label | string | — |
| placeholder | string | '' |
| rows | number | 4 |
| maxLength | number | — |
| helperText | string | — |
| error | string | — |
| density | 'small' \| 'medium' \| 'large' | 'medium' |
| resizable | 'none' \| 'vertical' \| 'both' | 'vertical' |
br-datepicker
Seletor de data com calendário dropdown. Valor no formato "dd/mm/aaaa".
<br-datepicker
label="Data de nascimento"
[(ngModel)]="dataNascimento"
[required]="true"
hint="Formato: dd/mm/aaaa"
></br-datepicker>| Input | Tipo | Padrão |
|-------|------|--------|
| label | string | — |
| placeholder | string | 'dd/mm/aaaa' |
| hint | string | — |
| error | string | — |
| required | boolean | false |
| block | boolean | true |
br-timepicker
Seletor de hora com painel de horas e minutos. Valor no formato "HH:MM".
<br-timepicker label="Horário" [(ngModel)]="horario" [step]="15"></br-timepicker>| Input | Tipo | Padrão |
|-------|------|--------|
| label | string | — |
| placeholder | string | 'HH:MM' |
| step | number | 5 |
| hint | string | — |
| error | string | — |
| required | boolean | false |
br-datetimepicker
Composição de br-datepicker + br-timepicker. Valor no formato "dd/mm/aaaa HH:MM".
<br-datetimepicker
label="Agendamento"
[(ngModel)]="agendamento"
[minuteStep]="15"
layout="horizontal"
></br-datetimepicker>| Input | Tipo | Padrão |
|-------|------|--------|
| label | string | — |
| dateLabel | string | 'Data' |
| timeLabel | string | 'Hora' |
| minuteStep | number | 5 |
| layout | 'horizontal' \| 'vertical' | 'horizontal' |
| hint | string | — |
| dateError | string | — |
| timeError | string | — |
Botões
br-button
Botão seguindo o padrão GovBR DS com suporte a emphasis, density, modo escuro e mais.
<!-- Emphasis (ênfase) -->
<br-button emphasis="primary" (clicked)="salvar()">Salvar</br-button>
<br-button emphasis="secondary" icon="download">Download</br-button>
<br-button emphasis="tertiary" icon="trash">Excluir</br-button>
<br-button emphasis="danger" icon="warning">Remover</br-button>
<!-- Density (densidade) -->
<br-button emphasis="primary" density="small">Pequeno</br-button>
<br-button emphasis="primary" density="medium">Médio</br-button>
<br-button emphasis="primary" density="large">Grande</br-button>
<!-- Circular (icon-only) -->
<br-button emphasis="primary" [circle]="true" icon="plus" density="large"></br-button>
<!-- Block (largura total) -->
<br-button emphasis="primary" [block]="true">Largura total</br-button>
<!-- Loading -->
<br-button emphasis="primary" [loading]="salvando">Salvando...</br-button>
<!-- Modo escuro (para fundos escuros) -->
<br-button emphasis="primary" [dark]="true">Modo escuro</br-button>
<br-button emphasis="secondary" [dark]="true">Outlined escuro</br-button>
<!-- Ícone à direita -->
<br-button emphasis="primary" icon="arrow-right" iconPosition="right">Próximo</br-button>
<!-- Estado ativo -->
<br-button emphasis="primary" [active]="true">Ativo</br-button>| Input | Tipo | Padrão | Descrição |
|-------|------|--------|-----------|
| emphasis | 'primary' \| 'secondary' \| 'tertiary' \| 'danger' | 'primary' | Nível de ênfase: primary (preenchido), secondary (outlined), tertiary (somente texto), danger |
| density | 'small' \| 'medium' \| 'large' | 'medium' | Densidade/tamanho |
| type | 'button' \| 'submit' \| 'reset' | 'button' | Tipo do botão HTML |
| icon | string | — | Ícone Font Awesome (sem fa-) |
| iconPosition | 'left' \| 'right' | 'left' | Posição do ícone |
| circle | boolean | false | Botão circular (icon-only) |
| block | boolean | false | Largura total |
| loading | boolean | false | Estado de carregamento com spinner |
| disabled | boolean | false | Desabilitado |
| active | boolean | false | Estado ativo/pressionado |
| dark | boolean | false | Modo escuro (cores invertidas para fundos escuros) |
Backward compatibility:
variantesizeainda funcionam como aliases paraemphasisedensity.
br-magic-button
Botão flutuante (FAB) com speed dial de ações rápidas.
<!-- FAB simples -->
<br-magic-button icon="plus" (fabClick)="criarNovo()"></br-magic-button>
<!-- FAB com ações -->
<br-magic-button icon="plus" [actions]="acoes" position="bottom-right" (actionClick)="onAction($event)"></br-magic-button>import { BrMagicAction } from '@schenkerjon/ng-govbr-tw';
acoes: BrMagicAction[] = [
{ id: 'doc', label: 'Novo documento', icon: 'file' },
{ id: 'foto', label: 'Tirar foto', icon: 'camera' },
{ id: 'msg', label: 'Nova mensagem', icon: 'envelope' },
];| Input | Tipo | Padrão |
|-------|------|--------|
| icon | string | 'plus' |
| actions | BrMagicAction[] | [] |
| variant | 'primary' \| 'secondary' \| 'danger' | 'primary' |
| size | 'medium' \| 'large' | 'large' |
| position | 'bottom-right' \| 'bottom-left' \| 'bottom-center' | 'bottom-right' |
| showLabels | boolean | true |
Dados
br-card
<!-- Card com imagem -->
<br-card
cardTitle="Título"
subtitle="Descrição breve"
imageSrc="assets/imagem.jpg"
imageRatio="16:9"
tag="Novo"
linkText="Ver mais"
linkRoute="/detalhes"
></br-card>
<!-- Card horizontal -->
<br-card layout="horizontal" cardTitle="Documento" imageSrc="assets/thumb.jpg"></br-card>
<!-- Card com ícone e footer customizado -->
<br-card cardTitle="Estatísticas" icon="chart-bar">
<p class="text-2xl font-bold">1.234</p>
<div card-footer>
<a href="#">Ver relatório</a>
</div>
</br-card>| Input | Tipo | Padrão |
|-------|------|--------|
| cardTitle | string | — |
| subtitle | string | — |
| icon | string | — |
| tag | string | — |
| imageSrc | string | — |
| imageAlt | string | — |
| imageRatio | '16:9' \| '4:3' \| '1:1' | '16:9' |
| layout | 'vertical' \| 'horizontal' | 'vertical' |
| linkText | string | — |
| linkRoute | string \| unknown[] | — |
| clickable | boolean | false |
Slots: [card-footer]
br-table
<br-table headerVariant="blue" [page]="page" [totalPages]="10" (pageChange)="page = $event">
<thead>
<tr><th>Nome</th><th>E-mail</th><th>Status</th></tr>
</thead>
<tbody>
@for (u of users; track u) {
<tr>
<td>{{ u.nome }}</td>
<td>{{ u.email }}</td>
<td><br-badge [variant]="u.ativo ? 'success' : 'danger'">{{ u.ativo ? 'Ativo' : 'Inativo' }}</br-badge></td>
</tr>
}
</tbody>
</br-table>| Input | Tipo | Padrão |
|-------|------|--------|
| headerVariant | 'blue' \| 'light' | 'blue' |
| page | number | 1 |
| totalPages | number | 1 |
br-badge
<br-badge variant="success">Ativo</br-badge>
<br-badge variant="danger">Inativo</br-badge>
<br-badge variant="warning">Pendente</br-badge>
<br-badge variant="neutral">Rascunho</br-badge>| Input | Tipo | Padrão |
|-------|------|--------|
| variant | 'primary' \| 'success' \| 'danger' \| 'warning' \| 'neutral' | 'primary' |
br-item / br-list
Lista estruturada de itens.
<br-list title="Documentos recentes" variant="card">
<br-item
title="Relatório Anual 2024"
subtitle="Atualizado em 15/01/2024"
icon="file-pdf"
tag="PDF"
[clickable]="true"
[showArrow]="true"
(itemClick)="abrirDoc('relatorio')"
>
<span item-meta class="text-xs text-gray-500">2.4 MB</span>
</br-item>
<br-item
title="João da Silva"
subtitle="Analista de Sistemas"
avatarSrc="assets/avatar.jpg"
[clickable]="true"
>
<div item-actions>
<br-button density="small" emphasis="secondary" icon="envelope" [circle]="true"></br-button>
</div>
</br-item>
</br-list>br-list:
| Input | Tipo | Padrão |
|-------|------|--------|
| title | string | — |
| subtitle | string | — |
| variant | 'default' \| 'bordered' \| 'card' | 'default' |
| role | 'list' \| 'listbox' \| 'menu' | 'list' |
br-item:
| Input | Tipo | Padrão |
|-------|------|--------|
| title | string | '' |
| subtitle | string | — |
| icon | string | — |
| avatarSrc | string | — |
| tag | string | — |
| clickable | boolean | false |
| showArrow | boolean | false |
| selected | boolean | false |
| disabled | boolean | false |
| variant | 'default' \| 'compact' | 'default' |
Slots: [item-meta], [item-actions]
Feedback
br-message
<br-message type="info" title="Informação">Sua solicitação foi recebida.</br-message>
<br-message type="success" [dismissible]="true">Cadastro realizado!</br-message>
<br-message type="warning" [autoDismiss]="5000" title="Atenção">Sessão expira em breve.</br-message>
<br-message type="danger" title="Erro">Falha ao processar.</br-message>| Input | Tipo | Padrão |
|-------|------|--------|
| type | 'success' \| 'danger' \| 'warning' \| 'info' | 'info' |
| title | string | — |
| dismissible | boolean | false |
| autoDismiss | number | — |
Método público: show() — reexibe a mensagem após dismiss.
br-modal
<br-modal
[isOpen]="modalAberto"
title="Confirmar exclusão"
size="small"
primaryText="Excluir"
(confirmed)="excluir()"
(canceled)="modalAberto = false"
(closed)="modalAberto = false"
>
<p>Tem certeza que deseja excluir?</p>
</br-modal>| Input | Tipo | Padrão |
|-------|------|--------|
| isOpen | boolean | false |
| title | string | '' |
| size | 'xsmall' \| 'small' \| 'medium' \| 'large' \| 'auto' | 'medium' |
| showCloseButton | boolean | true |
| primaryText | string | 'Confirmar' |
| cancelText | string | 'Cancelar' |
| primaryDisabled | boolean | false |
| loading | boolean | false |
| closeOnScrim | boolean | true |
| closeOnEscape | boolean | true |
| hasCustomFooter | boolean | false |
Slot: [modal-footer] — footer customizado (com [hasCustomFooter]="true")
br-loading
<br-loading size="medium"></br-loading>
<br-loading [progress]="75" [showPercentage]="true" label="Carregando..."></br-loading>| Input | Tipo | Padrão |
|-------|------|--------|
| size | 'small' \| 'medium' \| 'large' | 'medium' |
| progress | number | — |
| showPercentage | boolean | true |
| label | string | — |
br-tooltip
<br-tooltip text="Informação adicional" place="top">
<i class="fa-solid fa-circle-info"></i>
</br-tooltip>| Input | Tipo | Padrão |
|-------|------|--------|
| text | string | '' |
| place | 'top' \| 'bottom' \| 'left' \| 'right' | 'top' |
| variant | 'info' \| 'success' \| 'danger' \| 'warning' | 'info' |
| timer | number | — |
Utilitários
br-accordion
<br-accordion mode="single" [bordered]="true">
<br-accordion-item title="Seção 1" icon="file" [open]="true">
Conteúdo da seção 1.
</br-accordion-item>
<br-accordion-item title="Seção 2" badge="3">
Conteúdo da seção 2.
</br-accordion-item>
</br-accordion>| Input (accordion) | Tipo | Padrão |
|-------|------|--------|
| mode | 'single' \| 'multiple' | 'multiple' |
| variant | 'default' \| 'negative' | 'default' |
| bordered | boolean | true |
| Input (item) | Tipo | Padrão |
|-------|------|--------|
| title | string | '' |
| icon | string | — |
| badge | string \| number | — |
| open | boolean | false |
| disabled | boolean | false |
| density | 'small' \| 'medium' \| 'large' | 'medium' |
br-wizard
Stepper para fluxos multi-etapas.
<br-wizard [currentStep]="step" (stepChange)="step = $event" (complete)="onComplete()">
<br-wizard-step label="Dados Pessoais" icon="user">
<br-input label="Nome" [(ngModel)]="nome"></br-input>
<br-input label="CPF" [(ngModel)]="cpf"></br-input>
</br-wizard-step>
<br-wizard-step label="Endereço" icon="location-dot">
<br-input label="CEP" [(ngModel)]="cep"></br-input>
</br-wizard-step>
<br-wizard-step label="Confirmação" icon="check">
<p>Revise seus dados antes de enviar.</p>
</br-wizard-step>
</br-wizard>| Input | Tipo | Padrão |
|-------|------|--------|
| currentStep | number | 0 |
| variant | 'simple' \| 'numbered' | 'numbered' |
| showNavigation | boolean | true |
| allowJump | boolean | false |
| Output | Tipo |
|--------|------|
| stepChange | number |
| complete | void |
Métodos públicos: next(), previous(), goToStep(index)
br-cookiebar
Barra de consentimento de cookies (LGPD).
<br-cookiebar
[(visible)]="showCookies"
[cookieGroups]="cookieGroups"
(acceptAll)="onAcceptAll()"
(acceptSelected)="onAcceptSelected($event)"
(reject)="onReject()"
>
<p>
Este site utiliza cookies para melhorar sua experiência.
<a href="/politica" class="underline font-semibold">Política de Privacidade</a>.
</p>
</br-cookiebar>import { BrCookieGroup } from '@schenkerjon/ng-govbr-tw';
cookieGroups: BrCookieGroup[] = [
{ id: 'essential', label: 'Essenciais', description: 'Necessários para o site funcionar.', required: true, enabled: true },
{ id: 'analytics', label: 'Analíticos', description: 'Nos ajudam a entender o uso do site.', enabled: false },
{ id: 'marketing', label: 'Marketing', description: 'Exibir anúncios relevantes.', enabled: false },
];| Input | Tipo | Padrão |
|-------|------|--------|
| visible | boolean | false |
| cookieGroups | BrCookieGroup[] | [] |
| Output | Tipo |
|--------|------|
| acceptAll | void |
| acceptSelected | BrCookieGroup[] |
| reject | void |
| visibleChange | boolean |
Sidebar (alternativa ao br-menu)
Para layouts com sidebar colapsável estilo shadcn:
<br-sidebar [collapsed]="collapsed" (collapsedChange)="collapsed = $event" [collapsible]="true" [hasHeader]="true">
<div sidebar-header>Logo</div>
<br-sidebar-group>
<br-sidebar-group-label>Menu</br-sidebar-group-label>
<br-sidebar-item label="Dashboard" icon="gauge" route="/dashboard"></br-sidebar-item>
<br-sidebar-item label="Relatórios" icon="chart-bar" route="/relatorios" badge="5"></br-sidebar-item>
<br-sidebar-sub label="Configurações" icon="gear" [open]="true">
<br-sidebar-item label="Geral" route="/config/geral"></br-sidebar-item>
</br-sidebar-sub>
</br-sidebar-group>
<div sidebar-footer>Footer</div>
</br-sidebar>| Input | Tipo | Padrão |
|-------|------|--------|
| collapsed | boolean | false |
| collapsible | boolean | true |
| variant | 'sidebar' \| 'floating' \| 'inset' | 'sidebar' |
| hasHeader | boolean | false |
| hasFooter | boolean | false |
| mobileOpen | boolean | false |
Tokens de Cor
| Token | Cor |
|-------|-----|
| govbr-primary | #1351b4 |
| govbr-primary-dark | #0c326f |
| govbr-primary-darkest | #071d41 |
| govbr-primary-light | #c5d4eb |
| govbr-primary-lightest | #dbe8fb |
| govbr-success | #168821 |
| govbr-danger | #e52207 |
| govbr-warning | #ffcd07 |
| govbr-info | #155bcb |
| govbr-focus | #c2850c |
Exemplo Completo
import { Component } from '@angular/core';
import {
BrLayoutComponent, BrHeaderComponent, BrMenuComponent,
BrMenuItemComponent, BrFooterComponent, BrCardComponent,
} from '@schenkerjon/ng-govbr-tw';
@Component({
selector: 'app-root',
standalone: true,
imports: [
BrLayoutComponent, BrHeaderComponent, BrMenuComponent,
BrMenuItemComponent, BrFooterComponent, BrCardComponent,
],
template: `
<br-layout>
<br-header
systemTitle="Portal de Serviços"
systemSubtitle="Ministério da Economia"
logoSrc="assets/gov-logo.png"
(menuToggle)="menuOpen = $event"
(searchSubmit)="onSearch($event)"
></br-header>
<br-menu [open]="menuOpen" (openChange)="menuOpen = $event">
<br-menu-item label="Início" icon="house" route="/" [exact]="true"></br-menu-item>
<br-menu-item label="Serviços" icon="grid" route="/servicos"></br-menu-item>
<br-menu-item label="Documentos" icon="file" route="/docs" badge="3"></br-menu-item>
</br-menu>
<div class="max-w-4xl mx-auto">
<h2 class="text-xl font-bold mb-4">Bem-vindo</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<br-card cardTitle="Consultar CPF" icon="id-card" linkText="Acessar" linkRoute="/cpf"></br-card>
<br-card cardTitle="Emitir certidão" icon="file-certificate" linkText="Acessar" linkRoute="/certidao"></br-card>
</div>
</div>
<br-footer logoSrc="assets/gov-logo.png"></br-footer>
</br-layout>
`,
})
export class AppComponent {
menuOpen = true;
onSearch(query: string) { console.log('Busca:', query); }
}Licença
MIT
