@banxa-official/banxa-ui
v0.2.1
Published
Banxa's Vue 3 design system — accessible, themeable components built on a CSS custom property token cascade.
Maintainers
Readme
@banxa-official/banxa-ui
Banxa's Vue 3 design system — a set of accessible, themeable UI components built on a three-tier CSS custom property token cascade (primitives → semantic → component), with first-class TypeScript support and a dark-mode-first theme that can be fully overridden by consuming applications.
Installation
npm install @banxa-official/banxa-uivue (^3.2.0) is a peer dependency and must already be installed in your project.
Getting started
Import the components you need and the stylesheet once, globally, in your app's entry point:
// main.js / main.ts
import { createApp } from 'vue'
import App from './App.vue'
import '@banxa-official/banxa-ui/style.css'
createApp(App).mount('#app')Then use components directly in your .vue files:
<script setup>
import { ref } from 'vue'
import { BxButton, BxInput } from '@banxa-official/banxa-ui'
const email = ref('')
</script>
<template>
<BxInput v-model="email" label="Email address" placeholder="[email protected]" />
<BxButton variant="primary" @click="submit">Continue</BxButton>
</template>Only import what you use — the library is tree-shakeable, so unused components are dropped from your production bundle.
Available components
| Category | Components |
|------------|------------|
| Foundation | BxButton, BxIcon, BxDivider, BxBadge |
| Form | BxInput, BxSelect, BxSelectField, BxCombobox, BxCheckbox, BxRadio, BxSwitch, BxOtpInput |
| Feedback | BxAlert, BxToast, BxProgress, BxSpinner, BxDots, BxSkeleton |
| Surface | BxCard, BxModal, BxTooltip, BxDescriptionList |
| Navigation | BxDropdownMenu, BxDropdownMenuItem, BxTabs |
| Composite | BxCollapsible |
Browse every component, prop, and variant interactively in Storybook.
Theming
Components never hardcode colours — every visual token is a CSS custom property, applied at three tiers:
- Primitives — raw palette/scale values (
--space-16,--radius-standard, ...) - Semantic — what things mean (
--fills-cta,--fills-background,--fills-alert-error, ...) - Component — per-component hooks for narrow overrides (
--bx-button-bg, ...)
The library ships dark mode by default (tokens on :root) and a light mode you opt into
by adding a .lightmode class to any ancestor element (typically <html> or <body>):
document.documentElement.classList.toggle('lightmode', isLightMode)Overriding colours (brand/merchant theming)
Because every token is a real CSS custom property, a host application can override the whole palette without touching component code — just redeclare the variables on an ancestor element, after the library's stylesheet has loaded:
:root {
--fills-cta: #ff5a1f;
--fills-cta-hover: #e64f1a;
--fills-cta-active: #cc4517;
--fills-cta-foreground: #ffffff;
--fills-background: #0b0b0d;
}This works because CSS custom properties resolve via normal inheritance: a declaration on
a container element always wins over an inherited value from :root, regardless of
stylesheet load order — so it's safe to apply per-tenant/per-merchant theming at runtime
(e.g. via element.style.setProperty('--fills-cta', merchantColor)).
TypeScript support
The package ships its own type declarations (dist/index.d.ts, generated from source) —
no @types/* package needed. Component prop types, emitted event types, exported
composables, and shared types are all available out of the box:
import { BxSelect } from '@banxa-official/banxa-ui'
import type { SelectOption } from '@banxa-official/banxa-ui'
const options: SelectOption[] = [
{ label: 'USD', value: 'usd' },
{ label: 'EUR', value: 'eur' }
]moduleResolution: "bundler" or "node16"/"nodenext" (TS ≥ 4.7) is recommended so the
package's exports map resolves correctly. If you're on an older moduleResolution
setting and see "cannot find module" errors, upgrading moduleResolution is the fix —
this is a TypeScript project-config issue, not a missing dependency.
Error handling
Banxa UI surfaces problems in two different ways depending on whether they're part of your app's normal control flow or a mistake in how a component is used:
Validation / user-facing errors are just props — there's no exceptions to catch. Pass an
errormessage (or boolean, depending on the component) and the component renders its error styling and, where applicable, wires uparia-describedby/role="alert"for screen readers:<BxInput v-model="email" label="Email" :error="emailError" /> <BxButton variant="outlined" error>Delete account</BxButton>Developer-facing warnings (deprecated props/slots, unknown icon names, etc.) are logged via
console.warnand are automatically stripped out of production builds (import.meta.env.DEVguarded), so they never ship to end users:[BxInput] "hint" is deprecated. Use "description" instead. [BxIcon] Unknown icon name: "not-a-real-icon". Register it in registry.ts.Treat these as build-time linting signals — fix them before shipping, not something to handle at runtime.
Components do not throw during normal rendering; malformed input (e.g. an unrecognised icon name) degrades gracefully (renders nothing / falls back) rather than crashing your app.
Storybook
Every component includes a Storybook entry with variants, a dark/light theme toggle, and accessibility checks.
npm install
npm run storybookDevelopment
npm run build # Build the library (dist/)
npm run typecheck # vue-tsc
npm run lint # ESLint with --fix
npm run lint:check # ESLint, no autofix (CI)
npm run test:visual # Playwright visual regression tests against StorybookBrowser support
Targets evergreen browsers (Chrome, Firefox, Safari, Edge — last 2 versions). No IE11 support.
Contributing
Issues and merge requests are welcome. Please run npm run lint:check, npm run typecheck,
and npm run test:visual before opening a merge request.
