vael-ui
| Install | |
|---|---|
npm install vael-ui |
|
| Latest Version: | 0.4.8 |
| Vue: | 3 |
| License: | MIT |
| Last Updated: | Oct 21, 2026 |
| Links: | GitHub · npm |
vael-ui
A Vue 3 UI library with a real, first-class Vue Vapor build, plain CSS by default, animation-agnostic when you want more. One component per primitive, no compound-component sprawl, fully native to Vue's own APIs.
Docs & full component reference → vael-ui.dev
Vue Vapor support
Vue Vapor compiles templates straight to fine-grained reactive DOM updates instead of the classic virtual DOM (render → VNodes → diff → patch) — smaller runtime, faster updates. vael-ui ships both builds from the same package: every component is written once as a normal VDOM SFC, then compiled a second time through Vapor's compiler into a separate entry point.
import { Button } from 'vael-ui' // classic VDOM build
import { Button } from 'vael-ui/vapor' // compiled Vapor build, same props/API
The Vapor build needs Vue 3.6, which is still a prerelease. Pin the exact version vael-ui is
built against. A range such as ^3.5.0 can install Vue 3.5, which has no Vapor mode.
pnpm add vue@3.6.0-rc.12 --save-exact
A minimal Vapor app:
// main.ts
import { createVaporApp } from 'vue'
import App from './App.vue'
createVaporApp(App).mount('#app')
<!-- App.vue -->
<script setup vapor lang="ts">
import { Button, Toaster, toast } from 'vael-ui/vapor'
</script>
<template>
<Toaster />
<Button @click="toast('Saved')">Save</Button>
</template>
To compile every <script setup> component in your app as Vapor without the vapor
attribute, use vue({ features: { vapor: true } }) from @vitejs/plugin-vue 6.0.8 or later. vael-ui doesn't use the
Options API, so if your own components don't either, add optionsAPI: false to features to drop
its code from your bundle.
To move an existing VDOM app over a few components at a time, keep createApp and add
app.use(vaporInteropPlugin). Details: Vue Vapor support.
playground/vapor is a live showcase of the Vapor build with nothing else in the tree, every
mounted component there is genuinely Vapor, verified via Vue's own __vapor flag in
packages/vapor-ui/tests.
Install
pnpm add vael-ui
Usage
Each component loads its own CSS, so there is no stylesheet to import. On Tailwind v4, see the Tailwind guide for import order.
<script setup lang="ts">
import { Button, ConfigProvider } from 'vael-ui'
</script>
<template>
<ConfigProvider :theme="{ primary: '#6366f1', radius: '12px' }">
<Button @click="save">Save</Button>
</ConfigProvider>
</template>
Components use the page's font and ship none of their own, so set one on body
(for example font-family: system-ui, sans-serif).
Buttons and component text follow the font size on <html>. Set theme.fontSize to change text inside one provider:
<ConfigProvider :theme="{ fontSize: '14px' }">
<YourForm />
</ConfigProvider>
Set <html> to change the size across your app:
html {
font-size: 14px;
}
Use a CSS length such as 13px or 1rem, or an expression such as clamp(...). Font-size keywords such as small cannot be scaled by the component CSS.
Form fields follow it too. iOS zooms the page into a focused field under 16px, so if your text is smaller, call preventFocusZoom() once:
import { preventFocusZoom } from 'vael-ui'
preventFocusZoom() // iOS only; pinch-to-zoom keeps working
The library uses <html data-theme="dark"> for dark mode. Without a manual choice, it follows prefers-color-scheme. Add useColorScheme() to manage a toggle and save the choice through your persistence hook:
import { useColorScheme } from 'vael-ui'
const { mode, setMode } = useColorScheme({
persist: {
get: () => localStorage.getItem('theme'),
set: (m) => localStorage.setItem('theme', m ?? ''),
},
})
ConfigProvider applies scoped styles when Vue renders. To restore a saved color mode and app-wide font size before paint, copy the single HTML head script from the docs. Save CSS font sizes such as 13px under its app-font-size key. Persisted scoped font, radius, or primary overrides also need prepaint CSS or server-rendered values to avoid a flash.
ConfigProvider also sets app-wide defaults: size="sm" for a dense app, :motion-css="false" to turn off built-in animations (useful in tests), and dates and numbers follow the locale of the i18n you pass it.
Full theming/i18n/ConfigProvider setup: Global Setup guide.
Directives
v-tooltip and v-scroll-mask need global registration unless imported directly as
vTooltip/vScrollMask inside the same <script setup> that uses them:
import { createApp } from 'vue'
import { vTooltip, vScrollMask } from 'vael-ui'
import App from './App.vue'
const app = createApp(App)
app.directive('tooltip', vTooltip)
app.directive('scroll-mask', vScrollMask)
v-tooltip also needs a single <TooltipHost /> mounted once anywhere in your app (a shared
singleton every tooltip target renders through). Skipping either step is what causes a
Failed to resolve directive warning, or a tooltip that silently never shows.
Vapor apps import the same names from vael-ui/vapor instead. Full options and the
Vapor-specific directive shape: Animation Integration guide.
Server rendering
Both builds render on the server and hydrate in the browser. In Nuxt, add vael-ui/nuxt to
modules (Nuxt guide). With plain Vite SSR, set
ssr: { noExternal: ['vael-ui'] } so Vite bundles its CSS imports, and add ctx.teleports
to your page template, since overlays, toasts and tooltips teleport to <body>. See
Server rendering.
Structure
packages/
ui/ the library — publishes "vael-ui" + "vael-ui/vapor" from the same dist/
the only place any component is hand-authored
vapor-ui/ Vapor build/test tooling: compiles the generated tree into
packages/ui/dist/vapor, plus Vapor browser tests
scripts/ generate-vapor.mjs — copies each listed component into
vapor-ui/src/generated, marks it `vapor`, rewrites imports
playground/
vdom/ every primitive in CSS / motion-v / imperative flavors
vapor-interop/ a VDOM + Vapor mixed app
vapor/ standalone Vapor build showcase (vael-ui/vapor only)
docs/ the vael-ui.dev site — generated component reference + guides
Scripts
| Script | What it does |
|---|---|
pnpm build |
Builds the library (packages/ui/dist) and the Vapor variant (dist/vapor) |
pnpm typecheck |
Builds, then vue-tsc over every workspace package |
pnpm test |
Browser tests for the library (vitest + Playwright, real Chromium) |
pnpm test:vapor / test:vapor-interop |
Vapor build and interop verification |
pnpm play / play:vapor / play:vapor-interop |
Dev servers for each playground |
pnpm lint / pnpm format |
oxlint + eslint / oxfmt write |
pnpm changeset |
Describe a pending change for the next release |
The library depends on vael-ui's built dist/, not src/ — pnpm play alone silently
serves a stale build the moment you edit library source. Run pnpm --filter vael-ui dev
(tsdown --watch) alongside it, or rebuild after each change.
Contributing
pnpm install- Make your change, add tests where it makes sense
pnpm typecheck && pnpm testbefore opening a PR- Commits follow Conventional Commits — enforced by a commit-msg hook
- If your change affects the published
vael-uipackage, runpnpm changeset
Releases are automated: merging to main opens or updates a "Version Packages" PR from any
pending changesets; merging that PR publishes to npm.
Sponsor
If vael-ui saves you time, consider sponsoring its development on GitHub.
License
MIT
Related Packages
Librería de componentes UI en Vue 3 + TypeScript para estandarizar estilos entre...
A set of ready-to-use UI components for Vue 3, styled according to the Flowbite...
Banxa's Vue 3 design system — accessible, themeable components built on a CSS cu...
Version History
| Version | Released | License |
|---|---|---|
| 0.4.8 | MIT | |
| 0.4.7 | MIT | |
| 0.4.6 | MIT | |
| 0.4.5 | MIT | |
| 0.4.4 | MIT | |
| 0.4.3 | MIT | |
| 0.4.2 | MIT | |
| 0.4.1 | MIT | |
| 0.4.0 | MIT | |
| 0.3.11 | MIT | |
| 0.3.10 | MIT | |
| 0.3.9 | MIT | |
| 0.3.8 | MIT | |
| 0.3.7 | MIT | |
| 0.3.6 | MIT | |
| 0.3.5 | MIT | |
| 0.3.4 | MIT | |
| 0.3.3 | MIT | |
| 0.3.2 | MIT | |
| 0.3.1 | MIT | |
| 0.3.0 | MIT | |
| 0.2.9 | MIT | |
| 0.2.8 | MIT | |
| 0.2.7 | MIT | |
| 0.2.6 | MIT | |
| 0.2.5 | MIT | |
| 0.2.4 | MIT | |
| 0.2.3 | MIT | |
| 0.2.2 | MIT | |
| 0.2.1 | MIT |
Showing the latest 30 of 45. See every release on npm