Vue-native headless UI primitives - accessible, unstyled, and built for Vue.
Unlike libraries ported from React (Radix, Reka), Akaza UI is designed from scratch for Vue 3. It uses v-model, named scoped slots, and the ui prop as first-class primitives - no sub-component trees, no asChild, no fighting the framework.
| Others | Akaza UI |
|---|---|
<DialogRoot><DialogTrigger><DialogPortal><DialogOverlay><DialogContent> |
<Dialog v-model="isOpen"> with named slots |
| React-adapted DX | Vue-native: v-model, scoped slots, inject/provide |
| Styled or opinionated defaults | Fully unstyled - data-akaza-* attributes and class hooks only |
- Slot-based, not sub-component-based - named scoped slots (
#trigger,#header,#body,#footer) keep templates flat and readable v-model-native - all stateful components bind via standardv-modeluiprop for structural styling - pass class strings per part (ui.overlay,ui.content,ui.header) instead of wrapping sub-components- Items-based API for lists -
RadioGroup,Menu,Tabs,Select,Listbox,CheckboxGroup, andToggleGroupaccept data arrays; per-item rendering uses named slots - Accessible by default - WAI-ARIA roles, keyboard navigation, and focus management built in
pnpm add akaza-ui
# or
npm install akaza-uiImport the CSS in your app entry point:
// main.ts
import "akaza-ui/dist/akaza-ui.css";If you use Tailwind CSS, declare the akaza-reset layer before Tailwind so utility classes can override component base styles:
/* main.css */
@layer akaza-reset;
@import "tailwindcss";Use the built-in Nuxt module — it registers all components as auto-imports and injects the CSS automatically:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ["akaza-ui/nuxt"],
});No manual CSS import or component registration needed.
| Component | Description |
|---|---|
Accordion |
Single or multi-open collapsible item list |
AlertDialog |
Confirmation dialog with alertdialog semantics |
Avatar |
Image with fallback slot on load error |
Button |
Accessible button with disabled, loading, async click, and as support |
Calendar |
Locale-aware single, multiple, and range date grid |
Checkbox |
Tri-state checkbox (true, false, 'indeterminate') |
CheckboxGroup |
Multi-select checkbox list with an items-based API |
Collapsible |
Single show/hide region with animated height |
Combobox |
Editable input plus listbox selection, filtering, and creation |
ContextMenu |
Right-click menu positioned at the pointer |
DataTable |
Typed semantic table with custom cells, sorting, filtering, and selection |
DateField |
Locale-ordered segmented date entry with optional Calendar |
DateRangeField |
Segmented start/end entry with range validation and native forms |
DateRangePicker |
Date range entry plus collision-aware Calendar popup |
Dialog |
Modal dialog with focus trap, Escape, backdrop |
Drawer |
Side panel with slide-in animation (top, right, bottom, left) |
Editable |
Inline text editing with preview, draft, submit, and cancel states |
Field |
Label, description, and error wiring for controls |
Fieldset |
Native fieldset and legend wrapper for related controls |
Form |
Submit wrapper exposing FormData and native validity state |
Input |
Text input with Field integration and invalid state attrs |
Listbox |
Standalone single/multiple selection with filtering and virtualization |
Menu |
Dropdown menu with items-based API, submenus, checkbox/radio items |
Menubar |
Horizontal menu strip with cross-menu keyboard navigation |
Meter |
Read-only gauge for bounded numeric values |
NavigationMenu |
Site navigation with hover/focus flyout panels |
NumberField |
Spinbutton number input with increment/decrement and scrub support |
OverlayProvider |
Programmatic overlay mounting with useOverlay |
Pagination |
Page navigation with compact ranges, ellipses, controls, and links |
PinInput |
Multi-cell OTP/PIN input with paste distribution and form support |
Popover |
Click-triggered floating panel with auto-positioning |
Progress |
Progressbar with determinate and indeterminate support |
RadioGroup |
Accessible radio group with roving tabindex and custom item rendering |
Rating |
Rating input with fractional values, hover preview, and form support |
Select |
Listbox select with keyboard navigation, typeahead, and form submission |
Separator |
Horizontal or vertical divider, decorative or semantic |
Sidebar |
Responsive sidebar with collapse, resizing, and mobile dialog behavior |
AppLayout |
Application shell with region slots, scrolling, sticky bars, and overlay sides |
Slider |
Slider with pointer drag, keyboard step, and ARIA value metadata |
Stepper |
Multi-step progress and navigation with linear rules and panels |
Switch |
Binary toggle with WAI-ARIA switch role |
Tabs |
Accessible tab set with animated indicator, items-based API |
TagsInput |
Tokenized text input with keyboard editing, validation, and paste handling |
Toast |
Queued status/alert notifications with actions and direction-aware motion |
Toggle |
On/off button with aria-pressed |
ToggleGroup |
Single or multiple pressed values with roving focus |
Toolbar |
Command strip with roving focus across controls |
Tooltip |
Hover/focus tooltip with auto-positioning and delay |
Tree |
Hierarchical selection with lazy loading, propagation, and virtualization |
HoverPreviewCard |
Hover/focus rich preview for links and entities |
<script setup lang="ts">
import { ref } from "vue";
import { Dialog } from "akaza-ui";
const isOpen = ref(false);
</script>
<template>
<Dialog
v-model="isOpen"
:ui="{
overlay: 'fixed inset-0 bg-black/50 backdrop-blur-sm',
content:
'fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white rounded-xl shadow-xl w-full max-w-md',
header: 'flex items-center justify-between p-6 border-b',
body: 'p-6',
footer: 'flex justify-end gap-2 p-6 border-t',
}"
>
<template #trigger="{ toggle }">
<button @click="toggle">Open</button>
</template>
<template #header="{ close, titleId }">
<h2 :id="titleId">Confirm</h2>
<button @click="close">✕</button>
</template>
<template #body="{ descriptionId }">
<p :id="descriptionId">Are you sure you want to continue?</p>
</template>
<template #footer="{ close }">
<button @click="close">Cancel</button>
<button @click="close">Confirm</button>
</template>
</Dialog>
</template><script setup lang="ts">
import { Menu } from "akaza-ui";
const items = [
{ label: "Profile", onSelect: () => {} },
{ label: "Settings", onSelect: () => {} },
{ type: "separator" },
{ label: "Sign out", onSelect: () => {} },
];
</script>
<template>
<Menu :items="items">
<template #trigger="{ toggle }">
<button @click="toggle">Options</button>
</template>
</Menu>
</template><script setup lang="ts">
import { ref } from "vue";
import { Tabs } from "akaza-ui";
const activeTab = ref("overview");
const items = [
{ value: "overview", label: "Overview" },
{ value: "settings", label: "Settings" },
];
</script>
<template>
<Tabs v-model="activeTab" :items="items" aria-label="Main navigation">
<template #panel-overview>Overview content</template>
<template #panel-settings>Settings content</template>
</Tabs>
</template>Akaza UI is fully unstyled. Relevant structural elements expose:
data-akaza-state- primary state (open,closed,checked,disabled,loading)- granular
data-akaza-*attrs - orthogonal state (invalid,focused,dirty,filled) data-akaza-side- positioning side for floating elements (top,bottom,left,right)- semantic
akaza-*classes - stable CSS selectors for each documented part
Style via the ui prop (inject classes per structural part):
<Dialog :ui="{
overlay: 'fixed inset-0 bg-black/50 backdrop-blur-sm',
content: 'fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white rounded-xl shadow-xl w-full max-w-md',
header: 'flex items-center justify-between p-6 border-b',
body: 'p-6',
footer: 'flex justify-end gap-2 p-6 border-t',
}">Or target via CSS:
[data-akaza-state="open"] { … }
.akaza-dialog-overlay { … }
.akaza-dialog-content { … }- Vue
>=3.5.0
packages/
akaza-ui/ — publishable library (akaza-ui on npm)
src/
components/ — Vue component primitives
composables/ — internal + public composables (useOverlay)
utils/ — focusTrap, focusable helpers
tests/ — unit, Nuxt integration, axe, and cross-browser interaction tests
docs/ — documentation site (Nuxt + Nuxt UI)
Early development. API is not stable. Breaking changes may occur between minor versions.