A Vue-native headless UI library.

Accessible, unstyled primitives built from scratch for Vue 3. Use v-model, named scoped slots, and the ui prop without React-style sub-component trees.

TabsDemo.vue
<script setup lang="ts">
import { ref } from "vue";
import { Tabs } from "akaza-ui";

const tabs = [
  { value: "overview", label: "Overview" },
  { value: "usage", label: "Usage" },
];
const active = ref("overview");
</script>

<template>
  <Tabs v-model="active" :items="tabs">
    <template #panel-overview>
      Accessible behavior, your styles.
    </template>
  </Tabs>
</template>

Everything you need, nothing you don't

Fully Accessible

Built on WAI-ARIA patterns. Keyboard navigation, focus management, and screen reader support are handled for you out of the box.

Completely Unstyled

Zero default styles. Bring your own CSS, Tailwind, or any design system — full control over every pixel, no overrides needed.

Vue-Native Slots API

Composing UI feels natural in Vue. Use slots instead of sub-components — no Radix-style boilerplate, just idiomatic Vue templates.

Headless & Flexible

Components expose all state and behavior through slots and props. You control the markup — Akaza UI handles the logic.

Lightweight

No runtime bloat. Each component is self-contained with minimal dependencies, so you only ship what you actually use.

TypeScript First

Full type safety throughout. Slot props, component props, and emits are all typed — autocomplete works everywhere.

Complete form behavior, in one example.

Native validation, server errors, disabled groups, custom controls, and nested fields work together in one real flow.

What to try

  • Select a plan and raise seats to 5 or more to clear native validation.
  • Use slug admin, root, or billing to see server errors.
  • Use blocked@company.test to see an email server error. ops@example.com is valid.
  • Unlock billing profile to see nested disabled controls enter FormData.

Live checks

  • Plan is required.
  • Seats must be at least 5.

Server errors

None yet. Submit with reserved slug or blocked email to populate this.

Realtime data

{
  "ownerName": "",
  "ownerEmail": "ops@example.com",
  "workspaceSlug": "support",
  "plan": "(missing)",
  "seats": 3,
  "riskScore": 72,
  "permissions": [
    "read",
    "export"
  ],
  "billingLocked": true,
  "submittedBillingFields": "(disabled fieldset omitted from FormData)"
}
Workspace request

Nested fields share one semantic group, but each control keeps its own label, hint, and error.

Shown on the internal approval ticket.
ops@example.com is valid. Use blocked@company.test for a server error.
Lowercase URL key. Server owns reserved words.
Required custom select with disabled option.
Minimum 5. Initial value is intentionally invalid.
Slider still submits a native value with the form.
Nested controls

Checkboxes, switch, and disabled fieldset live inside the same submit flow.

Select all allowed permissions
Read customer recordsNeeded by support and operations.
Export reportsDownloads CSV files with customer data.
Admin changesCan invite users and edit billing settings.
Billing write accessRequires finance approval.
One disabled option is visible because real policy often leaks into forms.
Use locked billing profileTurn this off to edit the nested billing fieldset. Disabled fields are omitted from FormData.
Billing profile

Disabled fieldset with nested Akaza fields and native inputs.

No submit yet. Live values update on the left.

Add Akaza UI to your project.

Install the package, then choose a component.