vael-ui

Animation-agnostic Vue 3 UI library with full Vue Vapor support.
7,312 58
Install
npm install vael-ui
Latest Version:0.4.8
Vue:3
License:MIT
Last Updated:Oct 21, 2026
Links: GitHub  ·  npm
Maintainer: mini-sylar

vael-ui

npm version npm downloads license Sponsor

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

  1. pnpm install
  2. Make your change, add tests where it makes sense
  3. pnpm typecheck && pnpm test before opening a PR
  4. Commits follow Conventional Commits — enforced by a commit-msg hook
  5. If your change affects the published vael-ui package, run pnpm 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

integrasoft-shared-ui

Librería de componentes UI en Vue 3 + TypeScript para estandarizar estilos entre...

2,758
@mtktech/ui

Thư viện UI component dùng chung cho Vue 3 (MButton, MDataTable, MSidebar, ...)

1,240
birdpaper-ui

A Vue 3 component library for enterprise admin interfaces. 为企业中后台而生的 Vu...

5,350 47
futility-ui

A set of ready-to-use UI components for Vue 3, styled according to the Flowbite...

4,934 1
@banxa-official/banxa-ui

Banxa's Vue 3 design system — accessible, themeable components built on a CSS cu...

926

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