Claro
Vermelho, preto e branco.
UIv1.0.0Construa interfaces com HTML nativo, vermelho VEXARO e uma API que acompanha seu projeto.
Começar agora Ver dashboardVEXARO UI é uma biblioteca CSS-first sem frameworks. A identidade padrão usa vermelho, preto e branco, com cantos retos em todos os componentes. Verde e âmbar comunicam sucesso e aviso.
Use HTML semântico, CSS nativo e JavaScript apenas para interações. A versão 1.0.0 entrega todos os componentes dos cards VEX-UI-001 a VEX-UI-018, incluindo controles avançados e integração opcional.
Compatibilidade alvo: versões atuais de Chrome, Firefox, Edge e Safari com CSS Grid, dialog.showModal(), inert e ES Modules. Datepicker usa o calendário nativo do navegador; a aparência e os atalhos variam por plataforma. Consulte o contrato público e as alterações.
Copie os dois arquivos de dist/ para o projeto. Eles são independentes dos fontes. Em um servidor estático, use:
<!doctype html>
<html lang="pt-BR" data-vx-theme="light">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="dist/vexaro.css">
<script type="module" src="dist/vexaro.js"></script>
<title>Meu projeto VEXARO</title>
</head>
<body>
<main class="vx-container vx-py-8">
<h1>Meu projeto</h1>
<button class="vx-btn" type="button" data-vx-toggle="toast"
data-vx-message="Tudo pronto!">Testar notificação</button>
</main>
</body>
</html>Para abrir diretamente por file://, ou integrar com scripts clássicos, substitua o script por:
<script defer src="dist/vexaro.global.js"></script>A versão clássica expõe window.Vexaro. As duas versões inicializam os atributos data-vx-* automaticamente. Carregue apenas uma delas. Alternativamente, use css/vexaro.css e js/vexaro.js, preservando as pastas de origem.
O reset/reboot é global: normaliza box-sizing, margens, controles, tipografia e foco. Os componentes, utilitários e tokens têm prefixo vx-.
Tokens semânticos acompanham o tema. O vermelho primário é #b91c1c no claro e #ff3333 no escuro. Use --vx-color-primary em vez de fixar uma cor primitiva. Todos os raios de borda são 0 por padrão.
| Token | Valor | Prévia |
|---|---|---|
--vx-white | #ffffff | |
--vx-black | #000000 | |
--vx-neutral-50 | #fafafa | |
--vx-neutral-100 | #f5f5f5 | |
--vx-neutral-200 | #e5e5e5 | |
--vx-neutral-400 | #a3a3a3 | |
--vx-neutral-500 | #737373 | |
--vx-neutral-600 | #525252 | |
--vx-neutral-900 | #171717 | |
--vx-red-400 | #f87171 | |
--vx-red-500 | #ff3333 | |
--vx-red-700 | #b91c1c | |
--vx-slate-50 | #f8fafc | |
--vx-slate-100 | #f1f5f9 | |
--vx-slate-200 | #e2e8f0 | |
--vx-slate-400 | #94a3b8 | |
--vx-slate-500 | #64748b | |
--vx-slate-600 | #475569 | |
--vx-slate-800 | #1e293b | |
--vx-slate-900 | #0f172a | |
--vx-blue-300 | #93c5fd | |
--vx-blue-700 | #1d4ed8 | |
--vx-green-300 | #86efac | |
--vx-green-800 | #166534 | |
--vx-amber-300 | #fcd34d | |
--vx-amber-900 | #78350f | |
--vx-red-300 | #fca5a5 | |
--vx-red-800 | #991b1b |
| Token | Valor | Prévia |
|---|---|---|
--vx-space-0 | 0 | |
--vx-space-1 | 0.25rem | |
--vx-space-2 | 0.5rem | |
--vx-space-3 | 0.75rem | |
--vx-space-4 | 1rem | |
--vx-space-5 | 1.25rem | |
--vx-space-6 | 1.5rem | |
--vx-space-8 | 2rem | |
--vx-space-10 | 2.5rem | |
--vx-space-12 | 3rem | |
--vx-space-16 | 4rem |
| Token | Valor | Prévia |
|---|---|---|
--vx-font-sans | system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif | |
--vx-font-mono | ui-monospace, SFMono-Regular, Consolas, monospace | |
--vx-text-xs | 0.75rem | |
--vx-text-sm | 0.875rem | |
--vx-text-md | 1rem | |
--vx-text-lg | 1.125rem | |
--vx-text-xl | 1.25rem | |
--vx-text-2xl | 1.5rem | |
--vx-text-3xl | 2rem | |
--vx-text-4xl | 2.5rem | |
--vx-font-normal | 400 | |
--vx-font-medium | 500 | |
--vx-font-semibold | 600 | |
--vx-font-bold | 700 | |
--vx-leading-tight | 1.25 | |
--vx-leading-normal | 1.5 | |
--vx-leading-relaxed | 1.75 |
| Token | Valor | Prévia |
|---|---|---|
--vx-border-width | 1px | |
--vx-border-width-thick | 2px | |
--vx-radius-none | 0 | |
--vx-radius-sm | 0 | |
--vx-radius-md | 0 | |
--vx-radius-lg | 0 | |
--vx-radius-pill | 0 | |
--vx-focus-width | 3px | |
--vx-focus-offset | 3px |
| Token | Valor | Prévia |
|---|---|---|
--vx-shadow-none | none | |
--vx-shadow-sm | 0 1px 3px rgb(0 0 0 / 0.12) | |
--vx-shadow-md | 0 4px 12px rgb(0 0 0 / 0.16) | |
--vx-shadow-lg | 0 12px 32px rgb(0 0 0 / 0.2) |
| Token | Claro | Escuro |
|---|---|---|
--vx-color-bg | var(--vx-white) | var(--vx-black) |
--vx-color-surface | var(--vx-white) | var(--vx-neutral-900) |
--vx-color-surface-muted | var(--vx-neutral-100) | var(--vx-black) |
--vx-color-text | var(--vx-black) | var(--vx-white) |
--vx-color-text-muted | var(--vx-neutral-600) | var(--vx-neutral-200) |
--vx-color-border | var(--vx-neutral-500) | var(--vx-neutral-400) |
--vx-color-primary | var(--vx-red-700) | var(--vx-red-500) |
--vx-color-on-primary | var(--vx-white) | var(--vx-black) |
--vx-color-success | var(--vx-green-800) | var(--vx-green-300) |
--vx-color-on-success | var(--vx-white) | var(--vx-black) |
--vx-color-warning | var(--vx-amber-900) | var(--vx-amber-300) |
--vx-color-on-warning | var(--vx-white) | var(--vx-black) |
--vx-color-danger | var(--vx-red-800) | var(--vx-red-300) |
--vx-color-on-danger | var(--vx-white) | var(--vx-black) |
--vx-color-focus | var(--vx-red-700) | var(--vx-red-500) |
O tema claro é padrão. Defina o atributo no HTML ou em um contêiner. Temas locais mantêm suas cores quando o tema da página muda.
JavaScript: não
Vermelho, preto e branco.
Vermelho forte sobre preto.
<div class="vx-grid">
<article class="vx-card vx-col-12 vx-col-md-6" data-vx-theme="light">
<div class="vx-card-body"><h3>Claro</h3><p>Vermelho, preto e branco.</p><button class="vx-btn" type="button">Ação principal</button></div>
</article>
<article class="vx-card vx-col-12 vx-col-md-6" data-vx-theme="dark">
<div class="vx-card-body"><h3>Escuro</h3><p>Vermelho forte sobre preto.</p><button class="vx-btn" type="button">Ação principal</button></div>
</article>
</div>| Classe / atributo | Uso |
|---|---|
| data-vx-theme="light|dark" | Tema global ou local; funciona sem JS. |
| data-vx-toggle="theme" | Botão de alternância; requer JS. |
Carregue seu CSS depois da biblioteca e sobrescreva os pares de cor juntos. Temas explícitos redefinem cores no próprio escopo; personalize cada seletor necessário.
:root, [data-vx-theme="light"] {
--vx-color-primary: #a31515;
--vx-color-on-primary: #ffffff;
}
[data-vx-theme="dark"] {
--vx-color-primary: #ff3333;
--vx-color-on-primary: #000000;
}As cores primitivas azuis e slate permanecem disponíveis por compatibilidade; a identidade padrão usa vermelho e neutros. Alterações de paleta exigem nova validação de contraste. Escalas em rem acompanham a fonte raiz.
CSS Grid para layouts bidimensionais. Comece com 12 colunas no mobile e sobrescreva spans em breakpoints maiores.
JavaScript: não
<div class="vx-container-fluid">
<div class="vx-grid vx-gap-4">
<div class="vx-card vx-col-12 vx-col-md-4 vx-p-4">4 colunas no tablet</div>
<div class="vx-card vx-col-12 vx-col-md-8 vx-p-4">8 colunas no tablet</div>
</div>
</div>| Classe / atributo | Uso |
|---|---|
| vx-container / vx-container-fluid | Largura máxima responsiva / largura total, com padding lateral. |
| vx-grid / vx-grid-cols-12 | Grid de 12 colunas; gap padrão space-4. |
| vx-col-1 … vx-col-12 | Número de colunas ocupadas. |
| vx-col-{sm|md|lg|xl|xxl}-{1…12} | Spans por breakpoint mínimo. |
| Breakpoints | sm 576px · md 768px · lg 992px · xl 1200px · xxl 1400px |
| Containers | 540 / 720 / 960 / 1140 / 1320px nos respectivos breakpoints. |
Use Flexbox para barras de ações e alinhamentos em uma direção.
JavaScript: não
<div class="vx-flex vx-flex-wrap vx-items-center vx-justify-between vx-gap-4 vx-w-full">
<span class="vx-badge vx-badge-success">3 alterações salvas</span>
<div class="vx-flex vx-gap-2"><button type="button" class="vx-btn vx-btn-secondary">Cancelar</button><button type="button" class="vx-btn">Salvar</button></div>
</div>| Classe / atributo | Uso |
|---|---|
| vx-flex / vx-flex-row / vx-flex-col | Exibição e direção. |
| vx-flex-wrap / vx-flex-nowrap / vx-flex-1 / vx-flex-none | Quebra e crescimento. |
| vx-justify-start|end|center|between|around | Alinhamento principal. |
| vx-items-start|end|center|stretch / vx-self-center | Alinhamento cruzado. |
Use button para ações e links para navegação. Rótulos visíveis explicam a ação.
JavaScript: não
<button class="vx-btn vx-btn-primary" type="button">Primário</button>
<button class="vx-btn vx-btn-secondary" type="button">Secundário</button>
<button class="vx-btn vx-btn-outline" type="button">Contorno</button>
<button class="vx-btn vx-btn-ghost" type="button">Ghost</button>
<button class="vx-btn vx-btn-success" type="button">Confirmar</button>
<button class="vx-btn vx-btn-danger" type="button">Excluir</button>
<button class="vx-btn vx-btn-sm" type="button">Pequeno</button>
<button class="vx-btn vx-btn-lg" type="button">Grande</button>
<button class="vx-btn" type="button" disabled>Indisponível</button>
<button class="vx-btn" type="button" aria-busy="true" disabled>Salvando…</button>| Classe / atributo | Uso |
|---|---|
| vx-btn | Base; tamanho médio. |
| vx-btn-primary|secondary|outline|ghost|success|danger | Variantes semânticas. |
| vx-btn-sm / vx-btn-lg | Tamanhos. |
| disabled / aria-disabled="true" | Bloqueio nativo / semântica. JS do VEXARO impede cliques em aria-disabled; sem JS, a aplicação deve impedir a ativação de links. |
| aria-busy="true" | Indicador de carregamento. Use também disabled para bloquear ações repetidas. |
| --vx-color-primary / --vx-radius-md | Cor principal e raio (0 por padrão). |
Rótulos curtos para categorias e estados. A informação também aparece no texto.
JavaScript: não
<span class="vx-badge">Rascunho</span>
<span class="vx-badge vx-badge-primary">Em análise</span>
<span class="vx-badge vx-badge-success">Publicado</span>
<span class="vx-badge vx-badge-warning">Pendente</span>
<span class="vx-badge vx-badge-danger">Falhou</span>
<span class="vx-badge vx-badge-lg">Contador: 12</span>| Classe / atributo | Uso |
|---|---|
| vx-badge | Base neutra; estático. |
| vx-badge-primary|success|warning|danger | Cor contextual. |
| vx-badge-lg | Tamanho maior. |
Agrupe conteúdo com cabeçalho, corpo e rodapé opcionais.
JavaScript: não
Uma base compartilhada entre aplicação e documentação.
<article class="vx-card vx-card-elevated">
<header class="vx-card-header"><h3>Projeto VEXARO</h3></header>
<div class="vx-card-body"><span class="vx-badge vx-badge-success">Ativo</span><p class="vx-mt-4">Uma base compartilhada entre aplicação e documentação.</p></div>
<footer class="vx-card-footer"><a class="vx-btn" href="#quick-start">Começar projeto</a></footer>
</article>| Classe / atributo | Uso |
|---|---|
| vx-card / vx-card-header|body|footer | Superfície e estrutura. |
| vx-card-elevated / vx-card-borderless / vx-card-outlined | Sombra, sem borda ou borda espessa. |
| --vx-color-surface / --vx-shadow-md / --vx-radius-lg | Tokens de aparência. |
Feedback estático não precisa de live region. Em atualizações dinâmicas, use role="status" para rotina e role="alert" somente para urgência.
JavaScript: não
<div class="vx-alert vx-alert-info"><strong>Informação:</strong> sua sessão está ativa.</div>
<div class="vx-alert vx-alert-success"><strong>Sucesso:</strong> alterações salvas.</div>
<div class="vx-alert vx-alert-warning"><strong>Atenção:</strong> revise os campos.</div>
<div class="vx-alert vx-alert-danger"><strong>Erro:</strong> não foi possível salvar.</div>| Classe / atributo | Uso |
|---|---|
| vx-alert | Mensagem com padding e borda. |
| vx-alert-info|success|warning|danger | Variantes; combinam cor contextual e on-* correspondente. |
Controles nativos com labels e descrições associadas. A validação HTML5 continua funcionando sem JS.
JavaScript: não
<form class="vx-w-full" data-docs-form>
<div class="vx-field"><label class="vx-label" for="demo-name">Nome</label><input class="vx-input" id="demo-name" name="name" required autocomplete="name" aria-describedby="name-help"><span class="vx-help" id="name-help">Informe seu nome completo.</span></div>
<div class="vx-field"><label class="vx-label" for="demo-email">E-mail</label><input class="vx-input" type="email" id="demo-email" name="email" required autocomplete="email"></div>
<div class="vx-field"><label class="vx-label" for="demo-role">Perfil</label><select class="vx-select" id="demo-role" name="role"><option>Designer</option><option>Desenvolvedor</option></select></div>
<div class="vx-field"><label class="vx-label" for="demo-message">Mensagem</label><textarea class="vx-textarea" id="demo-message" name="message"></textarea></div>
<fieldset class="vx-p-4 vx-mb-4"><legend>Preferências</legend>
<label class="vx-check"><input class="vx-checkbox" type="checkbox" name="news"> Receber novidades</label>
<label class="vx-check"><input class="vx-radio" type="radio" name="plan" value="personal" checked> Pessoal</label>
<label class="vx-check"><input class="vx-radio" type="radio" name="plan" value="team"> Equipe</label>
<label class="vx-check"><input class="vx-switch" type="checkbox" role="switch" name="notifications"> Notificações</label>
</fieldset>
<div class="vx-field"><label class="vx-label" for="demo-invalid">Código com erro (exemplo estático)</label><input class="vx-input is-invalid" id="demo-invalid" value="ABC" aria-invalid="true" aria-describedby="code-error"><span class="vx-error" id="code-error">Use um código com seis dígitos.</span></div>
<div class="vx-field"><label class="vx-label" for="demo-readonly">Identificador somente leitura</label><input class="vx-input" id="demo-readonly" value="VX-001" readonly></div>
<div class="vx-field"><label class="vx-label" for="demo-disabled">Campo indisponível</label><input class="vx-input" id="demo-disabled" disabled value="Sem acesso"></div>
<button class="vx-btn" type="submit">Validar formulário</button>
</form>| Classe / atributo | Uso |
|---|---|
| vx-field / vx-label / vx-help / vx-error | Grupo, rótulo, ajuda e erro. |
| vx-input / vx-textarea / vx-select | Controles nativos. |
| vx-check / vx-checkbox / vx-radio / vx-switch | Seleção e alternância. |
| :user-invalid / .is-invalid / .vx-validated :invalid | Erro após interação, explícito ou validação do formulário. |
| aria-invalid / aria-describedby | Associe erro ao campo e atualize o estado na aplicação. |
Use caption, cabeçalhos com scope e um wrapper focável quando houver rolagem horizontal.
JavaScript: não
| Nome | Perfil | Status |
|---|---|---|
| Ana | Design | Ativa |
| Bruno | Engenharia | Pendente |
| 2 membros | ||
<div class="vx-table-responsive" role="region" aria-label="Equipe" tabindex="0">
<table class="vx-table vx-table-striped vx-table-bordered vx-table-hover vx-table-compact">
<caption>Membros da equipe</caption><thead><tr><th scope="col">Nome</th><th scope="col">Perfil</th><th scope="col">Status</th></tr></thead>
<tbody><tr><th scope="row">Ana</th><td>Design</td><td><span class="vx-badge vx-badge-success">Ativa</span></td></tr><tr><th scope="row">Bruno</th><td>Engenharia</td><td><span class="vx-badge vx-badge-warning">Pendente</span></td></tr></tbody>
<tfoot><tr><td colspan="3">2 membros</td></tr></tfoot>
</table>
</div>| Classe / atributo | Uso |
|---|---|
| vx-table | Tabela base. |
| vx-table-striped|bordered|hover|compact | Variantes combináveis. |
| vx-table-responsive | Rolagem horizontal; tabindex=0 permite acesso por teclado. |
Links reais representam destinos. A página atual usa aria-current="page"; itens indisponíveis não recebem href.
JavaScript: não
<nav aria-label="Trilha de navegação"><ol class="vx-breadcrumb"><li><a href="#inicio">Início</a></li><li><a href="#cards">Projetos</a></li><li aria-current="page">VEXARO UI</li></ol></nav>
<nav aria-label="Páginas de exemplo"><ol class="vx-pagination"><li><span aria-disabled="true">Anterior</span></li><li><a href="#contextual" aria-current="page">1</a></li><li><a href="#tabelas">2</a></li><li><a href="#tabelas">Próxima</a></li></ol></nav>| Classe / atributo | Uso |
|---|---|
| vx-breadcrumb / --vx-breadcrumb-separator | Trilha; separador padrão "/". |
| vx-pagination | Paginação semântica. |
| aria-current="page" / aria-disabled="true" | Página atual e item indisponível. |
| vx-tabs / vx-tab-item / vx-tab-link.is-active | Abas puramente visuais; use links para destinos e a versão JS para painéis. |
Um dialog nativo fornece camada superior e isolamento do conteúdo de fundo. O módulo gerencia foco, Tab, Escape, backdrop e retorno ao disparador.
JavaScript: sim
<button class="vx-btn" type="button" data-vx-toggle="modal" data-vx-target="#demo-modal">Abrir modal</button>
<dialog class="vx-modal" id="demo-modal" aria-labelledby="modal-title" tabindex="-1">
<header class="vx-modal-header"><h3 id="modal-title">Novo projeto</h3></header>
<div class="vx-modal-body"><label class="vx-label" for="project-name">Nome do projeto</label><input class="vx-input" id="project-name" autocomplete="off" autofocus></div>
<footer class="vx-modal-footer"><button class="vx-btn vx-btn-secondary" type="button" data-vx-dismiss="modal">Cancelar</button><button class="vx-btn" type="button" data-vx-dismiss="modal">Concluir</button></footer>
</dialog>| Classe / atributo | Uso |
|---|---|
| dialog.vx-modal / vx-modal-header|body|footer | Estrutura do diálogo. |
| data-vx-toggle="modal" / data-vx-target | Disparador declarativo. |
| data-vx-dismiss="modal" | Botão de fechar. |
| aria-labelledby | ID do título acessível. |
const modal = Vexaro.getInstance('#demo-modal');
modal.open();
modal.close();
// Eventos: vx:modal:open, vx:modal:closeNotificações dinâmicas com botão de descarte. O temporizador pausa com hover ou foco. Mensagens essenciais devem continuar disponíveis no conteúdo da página.
JavaScript: sim
<button class="vx-btn" type="button" data-vx-toggle="toast" data-vx-message="Projeto salvo com sucesso.">Mostrar notificação</button>| Classe / atributo | Uso |
|---|---|
| data-vx-toggle="toast" / data-vx-message | Cria mensagem de texto com temporizador padrão de 5 segundos. |
| data-vx-toast / data-vx-target | Permite usar uma notificação existente. |
| data-vx-dismiss="toast" | Descarte manual. |
| role="status" / role="alert" | Anúncio de rotina / urgente. |
const toast = Vexaro.Toast.show('Alterações salvas.', { duration: 5000 });
// duration: 0 mantém até descarte manual; urgent: true usa alert.
toast.close();
// Eventos: vx:toast:open, vx:toast:closeMenu de ações com setas, Home, End e Escape. Tab mantém a navegação natural; clicar ou mover o foco para fora fecha o menu.
JavaScript: sim
<div class="vx-dropdown">
<button class="vx-btn" type="button" data-vx-toggle="dropdown" data-vx-target="#demo-menu" aria-controls="demo-menu" aria-expanded="false">Ações</button>
<div class="vx-dropdown-menu" id="demo-menu" hidden><a href="#cards">Ver projetos</a><a href="#formularios">Editar perfil</a><button type="button" data-vx-toggle="toast" data-vx-message="Link copiado para demonstração.">Compartilhar</button></div>
</div>| Classe / atributo | Uso |
|---|---|
| vx-dropdown / vx-dropdown-menu | Contêiner e lista flutuante. |
| data-vx-toggle="dropdown" / data-vx-target | Inicialização declarativa. |
| aria-expanded / aria-haspopup | Gerenciados pelo módulo. |
const dropdown = Vexaro.getInstance('[data-vx-toggle="dropdown"]');
dropdown.open(); dropdown.close(); dropdown.toggle();
// Eventos: vx:dropdown:open, vx:dropdown:closeApenas uma aba participa da ordem de Tab. Setas alternam abas; Home e End vão à primeira e à última. Cada aba está associada ao próprio painel.
JavaScript: sim
<div class="vx-w-full">
<div class="vx-tabs" role="tablist" aria-label="Detalhes do projeto" data-vx-tabs id="demo-tabs">
<button class="vx-tab-link" role="tab" type="button" id="tab-overview" aria-controls="panel-overview" aria-selected="true">Visão geral</button>
<button class="vx-tab-link" role="tab" type="button" id="tab-history" aria-controls="panel-history" aria-selected="false" tabindex="-1">Histórico</button>
</div>
<div class="vx-tab-panel" role="tabpanel" id="panel-overview" aria-labelledby="tab-overview" tabindex="0">Tudo pronto para começar.</div>
<div class="vx-tab-panel" role="tabpanel" id="panel-history" aria-labelledby="tab-history" tabindex="0" hidden>Projeto criado hoje.</div>
</div>| Classe / atributo | Uso |
|---|---|
| data-vx-tabs / role="tablist" | Grupo de abas. |
| vx-tab-link / role="tab" / aria-controls | Botão e painel associado. |
| vx-tab-panel / role="tabpanel" / aria-labelledby | Painel e título. |
| aria-orientation="vertical" | Usa setas para cima e para baixo. |
const tabs = Vexaro.getInstance('#demo-tabs');
tabs.select(1); // índice ou elemento de aba
// Evento: vx:tabs:change; detail.tabA expansão anima a altura via CSS Grid. Conteúdo recolhido fica inert. Use single para manter apenas um item aberto; multiple permite vários.
JavaScript: sim
Não. Use HTML, CSS e JavaScript nativos.
Sim. Sobrescreva os tokens no seu CSS.
<div class="vx-accordion vx-w-full" data-vx-accordion="single">
<h3 class="vx-accordion-heading"><button class="vx-btn vx-btn-secondary" type="button" data-vx-toggle="collapse" data-vx-target="#answer-one" aria-expanded="false" aria-controls="answer-one">Preciso de framework?</button></h3>
<div class="vx-collapse" data-vx-collapse id="answer-one"><div class="vx-collapse-inner"><p class="vx-p-4">Não. Use HTML, CSS e JavaScript nativos.</p></div></div>
<h3 class="vx-accordion-heading"><button class="vx-btn vx-btn-secondary" type="button" data-vx-toggle="collapse" data-vx-target="#answer-two" aria-expanded="false" aria-controls="answer-two">Posso personalizar?</button></h3>
<div class="vx-collapse" data-vx-collapse id="answer-two"><div class="vx-collapse-inner"><p class="vx-p-4">Sim. Sobrescreva os tokens no seu CSS.</p></div></div>
</div>| Classe / atributo | Uso |
|---|---|
| data-vx-collapse / vx-collapse / vx-collapse-inner | Painel e filho interno obrigatório. |
| data-vx-toggle="collapse" / data-vx-target | Disparador. |
| data-vx-accordion="single|multiple" | Modo exclusivo ou múltiplo. |
| is-open | Estado inicial aberto. |
const collapse = Vexaro.getInstance('#answer-one');
collapse.open(); collapse.close(); collapse.toggle();
// Eventos: vx:collapse:open, vx:collapse:closeInformação complementar disponível ao focar e passar o mouse. Escape descarta. A dica aceita hover; conteúdo essencial deve continuar visível na página.
JavaScript: sim
<span class="vx-tooltip-wrap"><button class="vx-btn vx-btn-secondary" type="button" data-vx-toggle="tooltip" data-vx-target="#demo-tip">Ajuda sobre tokens</button><span class="vx-tooltip" id="demo-tip" role="tooltip" hidden>Tokens são variáveis CSS compartilhadas.</span></span>| Classe / atributo | Uso |
|---|---|
| vx-tooltip-wrap / vx-tooltip | Posicionamento e conteúdo. |
| data-vx-toggle="tooltip" / data-vx-target | Disparador. |
| aria-describedby | Preserva descrições existentes e acrescenta a dica. |
const tip = Vexaro.getInstance('[data-vx-toggle="tooltip"]');
tip.open(); tip.close();
// Eventos: vx:tooltip:open, vx:tooltip:closeConteúdo complementar acionado por clique. Escape e clique externo fecham. O foco segue a ordem natural; o popover não é modal.
JavaScript: sim
CSS-first, componentes nativos e API pública documentada.
<button class="vx-btn vx-btn-secondary" type="button" data-vx-toggle="popover" data-vx-target="#demo-popover" aria-controls="demo-popover" aria-expanded="false">Sobre a versão</button>
<div class="vx-popover" id="demo-popover" role="region" aria-labelledby="popover-title" hidden><h3 id="popover-title">VEXARO UI 1.0</h3><p>CSS-first, componentes nativos e API pública documentada.</p></div>| Classe / atributo | Uso |
|---|---|
| vx-popover | Painel fixo reposicionado no viewport. |
| data-vx-toggle="popover" / data-vx-target | Disparador. |
| aria-controls / aria-expanded | Associação e estado. |
const popover = Vexaro.getInstance('[data-vx-toggle="popover"]');
popover.open(); popover.close(); popover.toggle();
// Eventos: vx:popover:open, vx:popover:closeSeleção de data nativa. O navegador fornece localização, navegação do calendário e teclado. O valor público usa YYYY-MM-DD; min, max e required seguem HTML5.
JavaScript: sim
<div class="vx-field vx-w-full"><label class="vx-label" for="demo-date">Prazo</label><input class="vx-input" type="date" id="demo-date" data-vx-datepicker min="2026-01-01" max="2030-12-31" aria-describedby="date-help"><span class="vx-help" id="date-help">Escolha uma data entre 2026 e 2030.</span></div>| Classe / atributo | Uso |
|---|---|
| input[type="date"] / vx-input / data-vx-datepicker | Calendário nativo com API opcional. |
| min / max / required | Restrições nativas. |
| value | Formato ISO; valores fora dos limites lançam RangeError na API. |
const date = Vexaro.getInstance('#demo-date');
date.value = '2026-12-01';
// date.open() deve ser chamado durante uma ação do usuário.
// Evento: vx:datepicker:change; detail.valueLista filtrada por texto com foco mantido no campo. Setas navegam, Enter seleciona e Escape fecha. Aceita texto livre; valide opções obrigatórias na aplicação.
JavaScript: sim
<div class="vx-combobox vx-w-full" data-vx-combobox id="demo-combobox">
<label class="vx-label" for="demo-city">Cidade</label><input class="vx-input" id="demo-city" aria-describedby="city-help">
<span class="vx-help" id="city-help">Digite para filtrar e use as setas para selecionar.</span>
<ul class="vx-combobox-list" role="listbox" aria-label="Cidades" id="city-options" hidden><li role="option">São Paulo</li><li role="option">Rio de Janeiro</li><li role="option">Belo Horizonte</li><li role="option">Curitiba</li></ul>
</div>| Classe / atributo | Uso |
|---|---|
| data-vx-combobox / vx-combobox | Contêiner. |
| input / [role="listbox"] / [role="option"] | Campo e opções de texto. |
| aria-expanded / aria-activedescendant / aria-selected | Gerenciados pelo componente. |
const combo = Vexaro.getInstance('#demo-combobox');
combo.open(); combo.close();
// Evento: vx:combobox:change; detail.value
// Em uma instância manual: new Vexaro.Combobox(element, { options: ['A', 'B'] })Range nativo com valor visível sincronizado. Setas, Home e End são fornecidos pelo navegador.
JavaScript: sim
<div class="vx-field vx-w-full"><label class="vx-label" for="demo-range">Volume: <output id="range-value" for="demo-range">40</output>%</label><input class="vx-range" type="range" id="demo-range" min="0" max="100" step="5" value="40" data-vx-slider data-vx-output="#range-value"></div>| Classe / atributo | Uso |
|---|---|
| vx-range / input[type="range"] / data-vx-slider | Controle nativo. |
| data-vx-output | Seletor de output associado. |
| min / max / step | Limites e incremento. |
const slider = Vexaro.getInstance('#demo-range');
slider.value = 75;
// Evento: vx:slider:change; detail.value (número)Ordenação local de linhas já carregadas. A paginação exibe uma faixa de linhas e anuncia a página atual; não realiza requisições ao servidor.
JavaScript: sim
| VEXARO | 18 |
|---|---|
| Atlas | 7 |
| Norte | 12 |
| Centro | 3 |
| Sul | 9 |
<div class="vx-w-full">
<div class="vx-table-responsive" role="region" aria-label="Projetos ordenáveis" tabindex="0"><table class="vx-table vx-table-striped" id="demo-data-table" data-vx-table data-vx-page-size="2" data-vx-pagination="#table-pages">
<caption>Projetos — clique nos cabeçalhos para ordenar</caption><thead><tr><th scope="col"><button type="button" data-vx-sort="text">Projeto</button></th><th scope="col"><button type="button" data-vx-sort="number">Tarefas</button></th></tr></thead>
<tbody><tr><th scope="row">VEXARO</th><td>18</td></tr><tr><th scope="row">Atlas</th><td>7</td></tr><tr><th scope="row">Norte</th><td>12</td></tr><tr><th scope="row">Centro</th><td>3</td></tr><tr><th scope="row">Sul</th><td>9</td></tr></tbody>
</table></div>
<nav class="vx-flex vx-flex-wrap vx-items-center vx-gap-3 vx-mt-4" id="table-pages" aria-label="Páginas dos projetos"><button type="button" class="vx-btn vx-btn-secondary vx-btn-sm" data-vx-page="prev">Anterior</button><span data-vx-page-status role="status"></span><button type="button" class="vx-btn vx-btn-secondary vx-btn-sm" data-vx-page="next">Próxima</button></nav>
</div>| Classe / atributo | Uso |
|---|---|
| data-vx-table / data-vx-page-size / data-vx-pagination | Tabela, tamanho da página e controles. |
| data-vx-sort="text|number" | Botão de ordenação dentro de th. |
| data-vx-value | Valor opcional na célula para ordenar números formatados. |
| data-vx-page="prev|next" / data-vx-page-status | Controles e anúncio da paginação. |
const table = Vexaro.getInstance('#demo-data-table');
table.sort(1, 'descending', 'number');
table.goTo(2);
// Eventos: vx:table:sort (column, direction), vx:table:page (page)Utilitários são opcionais e carregados depois dos componentes. A escala disponível é 0, 1, 2, 3, 4, 5, 6, 8, 10, 12 e 16, referenciando --vx-space-*.
| Classe / atributo | Uso |
|---|---|
| vx-d-none|block|inline|inline-block|flex|grid | Display; !important para sobrepor o display do componente. |
| vx-m-* / vx-p-* / vx-gap-* | Margem, padding e gap. |
| vx-mx-* / vx-my-* / vx-px-* / vx-py-* | Eixos inline e block. |
| vx-mt-* / vx-mb-* / vx-ms-* / vx-me-* / vx-pt-* / vx-pb-* | Lados; ms/me seguem a direção de escrita. |
| vx-m-auto / vx-mx-auto / vx-ms-auto | Margens automáticas. |
| vx-d-md-flex / vx-p-lg-8 / vx-gap-sm-4 | Responsivos: mesmo conjunto sm/md/lg/xl/xxl. |
| vx-flex-md-row / vx-flex-lg-col | Direção responsiva. |
| vx-text-start|center|end / vx-text-muted / vx-w-full | Texto e largura. |
| vx-visible / vx-invisible / vx-sr-only | Visibilidade e conteúdo somente para leitores de tela. |
<div class="vx-d-none vx-d-md-flex vx-gap-4 vx-p-4 vx-p-lg-8">
Visível a partir de 768px; padding maior a partir de 992px.
</div>A entrada ESM exporta classes, versão e funções de ciclo de vida. A entrada global expõe os mesmos membros em Vexaro. Inicialização automática acontece uma vez ao carregar a página; para conteúdo adicionado depois, chame init novamente.
import { init, destroy, getInstance, Modal, Toast, setTheme } from './dist/vexaro.js';
const area = document.querySelector('#minha-area');
init(area); // idempotente: não duplica listeners ou instâncias
const modal = getInstance('#meu-modal');
modal.open();
modal.close();
Toast.show('Salvo.', { duration: 5000 });
setTheme('dark');
destroy(area); // remove listeners, temporizadores e referências antes de desmontar
// Ao voltar a montar: init(area)
// Instâncias manuais devem receber instance.destroy() explicitamente.| Classe / atributo | Uso |
|---|---|
| init(scope = document) | Retorna as novas instâncias; inclui o próprio scope se corresponder. |
| getInstance(element|selector) | Retorna instância auto-inicializada ou null. |
| destroy(scope = document) | Destrói instâncias registradas dentro do escopo. |
| instance.destroy() | Remove listeners e recursos de uma instância; não a reutilize após destroy. |
| setTheme("light"|"dark", element?) | Atualiza tema e dispara vx:theme:change. |
| vx:init:error | Erro de marcação: detail.error e registro no console. |
| Eventos vx:* | CustomEvent com bubbles=true. Dados específicos em detail. |
A API de cada componente está na respectiva seção. Apenas Modal deve prender o foco, enquanto estiver aberto. A biblioteca não injeta HTML de mensagens: textos de toast e combobox usam textContent.
A API pública está congelada na versão 1.0.0 conforme API.md. Classes, tokens e métodos documentados só podem ser removidos ou mudar de significado em uma versão major. Adições compatíveis usam minor; correções usam patch.
Em React, Vue e Svelte, importe o CSS uma vez e inicialize os componentes após montar o DOM. Chame destroy antes de desmontar. Use getInstance para componentes auto-inicializados; não crie uma segunda instância manual no mesmo elemento. Consulte os exemplos por framework.
import { init, destroy } from './dist/vexaro.js';
// Após montar:
init(container);
// Antes de desmontar:
destroy(container);import { registerVexaroElements } from './integrations/web-components.js';
registerVexaroElements();<vx-components>
<button class="vx-btn" type="button" data-vx-toggle="toast"
data-vx-message="Integração pronta.">Testar</button>
</vx-components>O adaptador observa conexão e desconexão. Para conteúdo inserido depois dentro do elemento, chame element.refresh(). Ele não é importado pelo núcleo e não exige framework ou Shadow DOM.
Use uma ordem coerente de títulos, labels visíveis e descrições associadas. Tab e Shift+Tab percorrem controles; Enter e Espaço ativam botões. Setas controlam abas, dropdowns, combobox e ranges. Escape fecha modal, dropdown, tooltip e popover.
Os 38 pares de contraste dos tokens são verificados: texto e cores semânticas com no mínimo 4,5:1; bordas e foco sobre fundos fornecidos com 3:1. Estados desabilitados têm opacidade reduzida. Cores personalizadas, imagens e combinações arbitrárias exigem avaliação própria.
Movimento reduzido desativa animações. O modal usa dialog nativo e devolve o foco ao fechar; painéis recolhidos ficam inert. Datepicker e range usam semântica e teclado do navegador. A biblioteca não certifica automaticamente a conformidade WCAG de uma aplicação.
node scripts/build.mjs
npm test
node scripts/browser-check.mjs
# Após instalar dependências de desenvolvimento:
npm run test:browser
npm run test:visual:updateO teste de navegador local usa Chrome headless e CDP; a suíte Playwright cobre Chromium e Firefox, screenshots e axe-core. A revisão humana de leitor de tela, ampliação e conteúdo final permanece necessária.
Consulte CHANGELOG.md para o histórico e o board para o estado de revisão.