Getting Started

Usage

Learn the core patterns for using Akaza UI components.

The slots API

Akaza UI uses Vue's native slot system. Components expose their state through scoped slot props — you render exactly what your design needs.

<script setup lang="ts">
import { Collapsible } from 'akaza-ui'
</script>

<template>
  <Collapsible :ui="{ trigger: 'px-4 py-3 hover:bg-neutral-50' }">
    <template #trigger="{ isOpen }">
      <span>Advanced settings</span>
    </template>

    <template #icon="{ isOpen }">
      <svg :class="{ 'rotate-180': isOpen }" .../>
    </template>

    <template #content>
      <p>Hidden until the trigger is activated.</p>
    </template>
  </Collapsible>
</template>

The ui prop

Most components accept a ui prop to inject CSS classes onto root and internal elements. Each key targets a named structural part:

<Accordion
  :items="items"
  :ui="{
    item: 'border-b border-neutral-200',
    trigger: 'px-4 py-3 font-medium hover:bg-neutral-50',
    content: 'px-4 pb-4 text-sm text-neutral-600',
  }"
/>

Use plain class for the root of single-root components. Use ui.root when styling root alongside internal parts. For multi-root or teleported components such as Dialog, AlertDialog, and Drawer, use named ui keys like overlay and content.

The available keys for each component are listed in that component's UI Options table. Exact CSS classes and data attributes are listed in Styling Hooks.

v-model

Components with open/close or value state support v-model:

<script setup lang="ts">
import { ref } from 'vue'
import { Dialog } from 'akaza-ui'

const open = ref(false)
</script>

<template>
  <Dialog v-model="open">
    <template #trigger="{ toggle }">
      <button @click="() => toggle()">Open dialog</button>
    </template>
    <template #body>Dialog content here.</template>
  </Dialog>
</template>

Programmatic control

Components that manage open state expose open, close, and toggle via defineExpose. Access them with a template ref:

<script setup lang="ts">
import { ref } from 'vue'
import { Dialog } from 'akaza-ui'

const dialog = ref()

function showConfirmation() {
  dialog.value?.open()
}
</script>

<template>
  <Dialog ref="dialog">
    <template #body>Are you sure?</template>
    <template #footer="{ close }">
      <button @click="() => close()">Dismiss</button>
    </template>
  </Dialog>

  <button @click="showConfirmation">Show confirmation</button>
</template>

Items-based API

List components (Tabs, Menu, RadioGroup, CheckboxGroup, Accordion) accept an items or options array. Per-item content uses named slots — no sub-component trees:

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

const active = ref('account')
const items = [
  { value: 'account', label: 'Account' },
  { value: 'security', label: 'Security' },
]
</script>

<template>
  <Tabs v-model="active" :items="items" aria-label="Settings">
    <template #panel-account>Account settings…</template>
    <template #panel-security>Security settings…</template>
  </Tabs>
</template>

Listening to events

Components emit typed events for state changes. The first argument is the next value. The second argument is details with reason, optional event, and cancel() for cancelable changes:

<Accordion
  :items="items"
  @value-change="(value, details) => {
    if (details.reason === 'trigger') console.log('opened:', value)
  }"
/>
<Dialog
  @open-change="(open) => analytics.track(open ? 'dialog_open' : 'dialog_close')"
/>

Each component's documentation lists its events in the Emits table.