Quick Start
This guide walks you through building a simple form using UI Kit components.
Prerequisites
Complete the Installation guide first.
Basic Usage
Importing Components
Import components individually for tree-shaking:
import { Button, Input } from '@gxp-dev/uikit'
Simple Button
<script setup lang="ts">
import { Button } from '@gxp-dev/uikit'
const handleClick = () => {
console.log('Button clicked!')
}
</script>
<template>
<Button @click="handleClick">
Click Me
</Button>
</template>
Button Variants
The Button component supports multiple visual variants:
<template>
<div class="flex gap-4">
<Button variant="default">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="destructive">Delete</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
</div>
</template>
Button Sizes
<template>
<div class="flex items-center gap-4">
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
<Button size="icon">
<IconPlus class="h-4 w-4" />
</Button>
</div>
</template>
Form Example
Basic Form
<script setup lang="ts">
import { ref } from 'vue'
import { Button, Input } from '@gxp-dev/uikit'
const email = ref('')
const password = ref('')
const handleSubmit = () => {
console.log('Submitted:', { email: email.value, password: password.value })
}
</script>
<template>
<form @submit.prevent="handleSubmit" class="space-y-4 max-w-sm">
<div class="space-y-2">
<label for="email" class="text-sm font-medium">
Email
</label>
<Input
id="email"
v-model="email"
type="email"
placeholder="you@example.com"
required
/>
</div>
<div class="space-y-2">
<label for="password" class="text-sm font-medium">
Password
</label>
<Input
id="password"
v-model="password"
type="password"
placeholder="Enter password"
required
/>
</div>
<Button type="submit" class="w-full">
Sign In
</Button>
</form>
</template>
Form with Validation States
<script setup lang="ts">
import { ref, computed } from 'vue'
import { Button, Input } from '@gxp-dev/uikit'
const email = ref('')
const isValid = computed(() => email.value.includes('@'))
const touched = ref(false)
</script>
<template>
<div class="space-y-2">
<Input
v-model="email"
type="email"
placeholder="Enter email"
:class="{ 'border-red-500': touched && !isValid }"
@blur="touched = true"
/>
<p v-if="touched && !isValid" class="text-sm text-red-500">
Please enter a valid email address
</p>
</div>
</template>
Styling Components
Using the class Prop
All components accept a class prop for custom styling:
<template>
<Button class="w-full rounded-full">
Full Width Rounded Button
</Button>
</template>
Using the cn() Utility
For conditional classes, use the included cn() utility:
<script setup lang="ts">
import { ref } from 'vue'
import { Button, cn } from '@gxp-dev/uikit'
const isLoading = ref(false)
</script>
<template>
<Button
:class="cn(
'transition-all',
isLoading && 'opacity-50 cursor-not-allowed'
)"
:disabled="isLoading"
>
{{ isLoading ? 'Loading...' : 'Submit' }}
</Button>
</template>
TypeScript Usage
Type-Safe Props
Components are fully typed:
<script setup lang="ts">
import { Button, type ButtonVariants } from '@gxp-dev/uikit'
// Type-safe variant prop
const variant: ButtonVariants['variant'] = 'secondary'
</script>
<template>
<Button :variant="variant">Typed Button</Button>
</template>
Component Events
<script setup lang="ts">
import { Input } from '@gxp-dev/uikit'
const handleUpdate = (value: string | number) => {
console.log('New value:', value)
}
</script>
<template>
<Input @update:modelValue="handleUpdate" />
</template>
Using with Icons
The UI Kit works well with icon libraries like Lucide:
npm install lucide-vue-next
<script setup lang="ts">
import { Button } from '@gxp-dev/uikit'
import { Mail, ArrowRight, Loader2 } from 'lucide-vue-next'
</script>
<template>
<div class="flex gap-4">
<!-- Icon on left -->
<Button>
<Mail class="mr-2 h-4 w-4" />
Email
</Button>
<!-- Icon on right -->
<Button>
Continue
<ArrowRight class="ml-2 h-4 w-4" />
</Button>
<!-- Loading state -->
<Button disabled>
<Loader2 class="mr-2 h-4 w-4 animate-spin" />
Please wait
</Button>
<!-- Icon only -->
<Button size="icon" variant="outline">
<Mail class="h-4 w-4" />
</Button>
</div>
</template>
Complete Example
Here's a complete login card example:
<script setup lang="ts">
import { ref } from 'vue'
import { Button, Input } from '@gxp-dev/uikit'
const email = ref('')
const password = ref('')
const isLoading = ref(false)
const handleSubmit = async () => {
isLoading.value = true
try {
// Your authentication logic here
await new Promise(resolve => setTimeout(resolve, 1000))
console.log('Login successful')
} finally {
isLoading.value = false
}
}
</script>
<template>
<div class="min-h-screen flex items-center justify-center bg-background">
<div class="w-full max-w-md p-8 space-y-6 bg-card rounded-lg shadow-lg">
<div class="text-center">
<h1 class="text-2xl font-bold text-card-foreground">
Welcome Back
</h1>
<p class="text-muted-foreground">
Sign in to your account
</p>
</div>
<form @submit.prevent="handleSubmit" class="space-y-4">
<div class="space-y-2">
<label for="email" class="text-sm font-medium">
Email
</label>
<Input
id="email"
v-model="email"
type="email"
placeholder="you@example.com"
required
:disabled="isLoading"
/>
</div>
<div class="space-y-2">
<label for="password" class="text-sm font-medium">
Password
</label>
<Input
id="password"
v-model="password"
type="password"
placeholder="Enter password"
required
:disabled="isLoading"
/>
</div>
<Button
type="submit"
class="w-full"
:disabled="isLoading"
>
{{ isLoading ? 'Signing in...' : 'Sign In' }}
</Button>
</form>
<div class="text-center">
<Button variant="link">
Forgot password?
</Button>
</div>
</div>
</div>
</template>
Next Steps
- Button Component - Full Button API reference
- Input Component - Full Input API reference
- Theming - Customize colors and styles
- Adding Components - Add more shadcn components