Vue Guide
@hanzo/ui provides native Vue 3 components using the Composition API. All components are fully typed with TypeScript and support both <script setup>
and Options API.
Installation
Install the package
npm install @hanzo/ui
# or
pnpm add @hanzo/ui
Install Vue and dependencies
npm install vue
npm install -D tailwindcss postcss autoprefixer
Configure Tailwind
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
"./node_modules/@hanzo/ui/**/*.{js,ts,jsx,tsx,vue}",
],
theme: {
extend: {},
},
plugins: [],
}
Usage
Script Setup (Recommended)
<script setup lang="ts">
import { Button, Card, Input } from '@hanzo/ui/vue'
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<Card>
<Button @click="count++">
Clicked {{ count }} times
</Button>
<Input v-model="count" type="number" />
</Card>
</template>
Options API
<script lang="ts">
import { defineComponent } from 'vue'
import { Button, Card } from '@hanzo/ui/vue'
export default defineComponent({
components: { Button, Card },
data() {
return {
count: 0
}
}
})
</script>
<template>
<Card>
<Button @click="count++">Count: {{ count }}</Button>
</Card>
</template>
Composables
Use Vue composables for state management:
<script setup>
import { Dialog, Button } from '@hanzo/ui/vue'
import { useDialog } from '@hanzo/ui/vue/composables'
const { open, close, isOpen } = useDialog()
</script>
<template>
<Button @click="open">Open Dialog</Button>
<Dialog :open="isOpen" @update:open="close">
<DialogContent>
<DialogTitle>Hello Vue!</DialogTitle>
</DialogContent>
</Dialog>
</template>
Form Handling
With VeeValidate
<script setup>
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Form, Input, Button } from '@hanzo/ui/vue'
const schema = toTypedSchema(
z.object({
email: z.string().email(),
password: z.string().min(8),
})
)
const { handleSubmit } = useForm({
validationSchema: schema,
})
const onSubmit = handleSubmit((values) => {
console.log(values)
})
</script>
<template>
<form @submit="onSubmit">
<Form.Field name="email">
<Form.Label>Email</Form.Label>
<Form.Control>
<Input type="email" />
</Form.Control>
</Form.Field>
<Button type="submit">Submit</Button>
</form>
</template>
Component Coverage
Available (~90% coverage):
- Alert, Avatar, Badge, Button, Card
- Checkbox, Dialog, Input, Label, Progress
- Radio, Select, Separator, Skeleton, Switch
- Tabs, Textarea, Toast, Toggle, Table
In Progress:
- Popover (🚧 Beta)
- Sheet (🚧 Beta)
- Some advanced animations
Not Available:
- Complex 3D components
- Some AI-specific components
TypeScript Support
Full type inference and checking:
<script setup lang="ts">
import type { ButtonProps } from '@hanzo/ui/vue'
import { Button } from '@hanzo/ui/vue'
interface MyButtonProps extends ButtonProps {
loading?: boolean
}
const props = defineProps<MyButtonProps>()
</script>
<template>
<Button :disabled="loading" v-bind="$attrs">
<slot v-if="!loading" />
<span v-else>Loading...</span>
</Button>
</template>
Nuxt Integration
<!-- pages/index.vue -->
<script setup>
import { Button, Card } from '@hanzo/ui/vue'
</script>
<template>
<Card>
<h1>Welcome to Nuxt</h1>
<Button>Click me</Button>
</Card>
</template>
Nuxt Config
// nuxt.config.ts
export default defineNuxtConfig({
css: ["@hanzo/ui/styles"],
modules: [],
tailwindcss: {
config: {
content: ["./node_modules/@hanzo/ui/**/*.vue"],
},
},
})
Best Practices
-
Use Composition API
- Better TypeScript support
- More composable and reusable
-
Use
<script setup>
- Less boilerplate
- Better performance
-
Type Your Props
const props = defineProps<{ title: string }>()
-
Use Provide/Inject for Deep Props
provide('theme', theme) const theme = inject('theme')