Skip to content

UI Components Library

A comprehensive collection of 40+ production-ready UI components built with shadcn-vue, Radix Vue, and TailwindCSS. Each component is designed with accessibility, performance, and developer experience in mind.

🧩 40+ Components

Complete set of UI components covering all common interface patterns and interactions

♿ Accessibility First

Built with Radix Vue primitives ensuring WCAG compliance and keyboard navigation

🎨 Design System

Consistent styling with CSS variables, semantic tokens, and automatic dark mode

📱 Responsive

Mobile-first design with responsive breakpoints and touch-friendly interactions

🔧 Customizable

Easy theming with CSS variables and utility classes for rapid customization

⚡ Performance

Tree-shakable components with minimal bundle impact and optimized rendering

Essential form controls and input components for data collection.

Button

High Usage • Primary, secondary, outline, ghost variants with sizes and loading states.

Examples: Submit buttons, CTAs, navigation actions

Input

High Usage • Text inputs with validation states, icons, and helper text support.

Examples: Search fields, form inputs, filters

Select

High Usage • Dropdown selection with search, multi-select, and grouping options.

Examples: Country selection, category filters, option lists

Checkbox

Medium Usage • Single and group checkboxes with indeterminate states.

Examples: Terms acceptance, bulk selections, feature toggles

Radio Group

Medium Usage • Exclusive selection controls with custom styling options.

Examples: Payment methods, preferences, single choice questions

Switch

Medium Usage • Toggle controls for boolean settings and feature flags.

Examples: Dark mode toggle, notification settings, feature switches

Slider

Medium Usage • Range inputs for numeric values with step controls.

Examples: Price ranges, volume controls, rating inputs

Textarea

Medium Usage • Multi-line text inputs with resize controls and validation.

Examples: Comments, descriptions, feedback forms

Navigation and routing components for seamless user journeys.

Navigation Menu

High Usage • Multi-level navigation with dropdown support and active states.

Examples: Main navigation, sidebar menus, header navigation

Breadcrumb

High Usage • Hierarchical navigation with customizable separators and icons.

Examples: Page navigation, category paths, step indicators

Pagination

High Usage • Page navigation with customizable page sizes and jump controls.

Examples: Table pagination, search results, content lists

Tabs

High Usage • Content organization with horizontal and vertical orientations.

Examples: Settings panels, content categories, data views

Sidebar

High Usage • Collapsible navigation panel with nested menu support.

Examples: Admin dashboards, app navigation, filter panels

Menubar

Medium Usage • Application-level menu with keyboard shortcuts and submenus.

Examples: Desktop app menus, context menus, action bars

User feedback and notification components for better UX.

Alert

High Usage • Status messages with severity levels and dismissible options.

Examples: Success messages, error notifications, warning alerts

Toast (Sonner)

High Usage • Non-blocking notifications with actions and auto-dismiss.

Examples: Save confirmations, error messages, action feedback

Dialog

High Usage • Modal dialogs with backdrop, focus management, and keyboard handling.

Examples: Confirmations, forms, detailed views

Alert Dialog

Medium Usage • Confirmation dialogs for destructive or important actions.

Examples: Delete confirmations, logout prompts, irreversible actions

Sheet

Medium Usage • Slide-in panels from screen edges with overlay support.

Examples: Mobile menus, filter panels, detail views

Tooltip

Medium Usage • Contextual help text with positioning and delay controls.

Examples: Icon explanations, help text, additional information

Popover

Medium Usage • Floating content containers with positioning and interactions.

Examples: Action menus, help content, additional options

Hover Card

Low Usage • Rich hover previews with detailed content and media.

Examples: User profiles, link previews, detailed tooltips

Components for organizing and presenting information.

Table

High Usage • Data tables with sorting, filtering, and selection capabilities.

Examples: User lists, data grids, reports

Badge

High Usage • Status indicators and labels with color variants.

Examples: Status labels, tags, notifications counts

Avatar

High Usage • User profile images with fallbacks and status indicators.

Examples: User profiles, comment authors, team members

Card

High Usage • Content containers with headers, footers, and flexible layouts.

Examples: Dashboard widgets, product cards, content blocks

Separator

Medium Usage • Visual dividers for content sections and grouping.

Examples: Menu separators, content dividers, section breaks

Skeleton

Medium Usage • Loading placeholders matching content structure.

Examples: Loading states, content placeholders, progressive loading

Progress

Medium Usage • Progress indicators for tasks and loading states.

Examples: File uploads, form completion, loading progress

Accordion

Medium Usage • Collapsible content sections with smooth animations.

Examples: FAQ sections, settings panels, content organization

Structural components for page layout and content organization.

Aspect Ratio

Medium Usage • Responsive containers maintaining specific aspect ratios.

Examples: Video containers, image placeholders, responsive media

Scroll Area

Medium Usage • Custom scrollable containers with styled scrollbars.

Examples: Content areas, lists, code blocks

Carousel

Low Usage • Image and content sliders with navigation controls.

Examples: Image galleries, testimonials, feature showcases

Stepper

Low Usage • Step-by-step process indicators with completion states.

Examples: Multi-step forms, onboarding flows, progress tracking

Advanced components for specific use cases.

Calendar

Medium Usage • Date selection with range support and customizable views.

Examples: Date pickers, event scheduling, booking systems

Date Picker

High Usage • Integrated date selection with input and calendar components.

Examples: Form date fields, filtering, event creation

Dropdown Menu

High Usage • Context menus with actions, separators, and sub-menus.

Examples: Action menus, context menus, option lists

Form

High Usage • Form layout components with validation and error handling.

Examples: Registration forms, settings, data entry

Label

High Usage • Accessible form labels with required indicators.

Examples: Form labels, field descriptions, input associations

Tags Input

Medium Usage • Multi-value input with tag creation and deletion.

Examples: Skill tags, categories, keywords

Number Field

Medium Usage • Numeric inputs with increment/decrement controls.

Examples: Quantity selectors, numeric settings, counters

Pin Input

Low Usage • One-time password and PIN entry with auto-focus.

Examples: 2FA codes, PIN verification, security codes

Range Calendar

Low Usage • Date range selection with start and end date support.

Examples: Booking periods, date filters, reporting ranges

<template>
<div class="space-x-2">
<!-- Primary Button -->
<Button>Primary</Button>
<!-- Secondary Button -->
<Button variant="secondary">Secondary</Button>
<!-- Outline Button -->
<Button variant="outline">Outline</Button>
<!-- Ghost Button -->
<Button variant="ghost">Ghost</Button>
<!-- Destructive Button -->
<Button variant="destructive">Delete</Button>
<!-- Loading Button -->
<Button :disabled="loading">
<Loader2 v-if="loading" class="mr-2 h-4 w-4 animate-spin" />
{{ loading ? 'Saving...' : 'Save' }}
</Button>
</div>
</template>
<script setup lang="ts">
import { Button } from '@/components/ui/button'
import { Loader2 } from 'lucide-vue-next'
const loading = ref(false)
</script>

The UI library uses a sophisticated CSS variables system for consistent theming:

:root {
/* Color Palette */
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96%;
--secondary-foreground: 222.2 84% 4.9%;
--muted: 210 40% 96%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96%;
--accent-foreground: 222.2 84% 4.9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 221.2 83.2% 53.3%;
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
/* ... dark mode variables */
}
<template>
<div class="theme-provider">
<!-- Components automatically adapt to theme -->
<Card>
<CardHeader>
<CardTitle>Theme-Aware Component</CardTitle>
<CardDescription>
This card automatically adapts to light/dark mode
</CardDescription>
</CardHeader>
<CardContent>
<Button>Primary Button</Button>
<Button variant="secondary">Secondary Button</Button>
</CardContent>
</Card>
</div>
</template>
<style>
/* Theme detection happens automatically via CSS media queries */
@media (prefers-color-scheme: dark) {
:root {
/* Dark mode CSS variables applied automatically */
}
}
</style>
/* Custom brand colors */
:root {
--primary: 142 76% 36%; /* Custom green */
--secondary: 210 40% 96%; /* Light gray */
--accent: 142 76% 90%; /* Light green */
--destructive: 0 84% 60%; /* Red for errors */
/* Chart colors for data visualization */
--color-chart-1: 142 76% 36%;
--color-chart-2: 197 71% 73%;
--color-chart-3: 43 74% 66%;
--color-chart-4: 27 87% 67%;
--color-chart-5: 15 86% 65%;
}
.dark {
--primary: 142 76% 40%; /* Brighter in dark mode */
--secondary: 217.2 32.6% 17.5%;
--accent: 142 76% 15%;
/* ... other dark mode adjustments */
}

Most components follow consistent API patterns:

PropTypeDefaultDescription
asstring | ComponentComponent defaultChange the component’s rendered element
as-childbooleanfalseMerge props into immediate child
classstring-Additional CSS classes
variantstring’default’Visual variant of the component
sizestring’default’Size variant of the component
// Button component variants
type ButtonVariant =
| 'default'
| 'destructive'
| 'outline'
| 'secondary'
| 'ghost'
| 'link'
type ButtonSize =
| 'default'
| 'sm'
| 'lg'
| 'icon'
// Usage examples
<Button variant="outline" size="sm">Small Outline</Button>
<Button variant="destructive" size="lg">Large Destructive</Button>
<Button variant="ghost" size="icon"><Settings /></Button>
<script setup lang="ts">
// ✅ Good: Import only needed components
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Card, CardContent } from '@/components/ui/card'
// ❌ Avoid: Importing entire UI library
// import * as UI from '@/components/ui'
</script>
<template>
<!-- ✅ Good: Proper ARIA labels and keyboard support -->
<Dialog>
<DialogTrigger as-child>
<Button aria-describedby="dialog-description">
Open Settings
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Settings</DialogTitle>
<DialogDescription id="dialog-description">
Customize your application preferences
</DialogDescription>
</DialogHeader>
<!-- Dialog content -->
</DialogContent>
</Dialog>
<!-- ✅ Good: Form labels and descriptions -->
<FormItem>
<FormLabel for="username">Username</FormLabel>
<FormControl>
<Input
id="username"
aria-describedby="username-description"
v-model="username"
/>
</FormControl>
<FormDescription id="username-description">
Choose a unique username for your account
</FormDescription>
</FormItem>
</template>
<template>
<Card class="w-full max-w-md">
<CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle class="text-sm font-medium">Total Revenue</CardTitle>
<DollarSign class="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div class="text-2xl font-bold">$45,231.89</div>
<p class="text-xs text-muted-foreground">
+20.1% from last month
</p>
<div class="mt-4">
<Progress :value="65" class="w-full" />
</div>
</CardContent>
</Card>
</template>
<script setup lang="ts">
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Progress } from '@/components/ui/progress'
import { DollarSign } from 'lucide-vue-next'
</script>
<template>
<form @submit="handleSubmit" class="space-y-8 max-w-2xl">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Personal Information -->
<div class="space-y-4">
<h3 class="text-lg font-semibold">Personal Information</h3>
<FormItem>
<FormLabel for="firstName">First Name</FormLabel>
<FormControl>
<Input id="firstName" v-model="form.firstName" />
</FormControl>
<FormMessage>{{ errors.firstName }}</FormMessage>
</FormItem>
<FormItem>
<FormLabel for="lastName">Last Name</FormLabel>
<FormControl>
<Input id="lastName" v-model="form.lastName" />
</FormControl>
<FormMessage>{{ errors.lastName }}</FormMessage>
</FormItem>
<FormItem>
<FormLabel>Country</FormLabel>
<Select v-model="form.country">
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select your country" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="us">United States</SelectItem>
<SelectItem value="ca">Canada</SelectItem>
<SelectItem value="uk">United Kingdom</SelectItem>
</SelectContent>
</Select>
<FormMessage>{{ errors.country }}</FormMessage>
</FormItem>
</div>
<!-- Preferences -->
<div class="space-y-4">
<h3 class="text-lg font-semibold">Preferences</h3>
<FormItem class="flex flex-row items-start space-x-3 space-y-0">
<FormControl>
<Checkbox v-model:checked="form.newsletter" />
</FormControl>
<div class="space-y-1 leading-none">
<FormLabel>Email notifications</FormLabel>
<FormDescription>
Receive email updates about your account
</FormDescription>
</div>
</FormItem>
<FormItem class="flex flex-row items-center justify-between rounded-lg border p-4">
<div class="space-y-0.5">
<FormLabel class="text-base">Dark Mode</FormLabel>
<FormDescription>
Enable dark mode for the interface
</FormDescription>
</div>
<FormControl>
<Switch v-model:checked="form.darkMode" />
</FormControl>
</FormItem>
</div>
</div>
<div class="flex justify-end space-x-2">
<Button type="button" variant="outline" @click="handleCancel">
Cancel
</Button>
<Button type="submit" :disabled="isSubmitting">
<Loader2 v-if="isSubmitting" class="mr-2 h-4 w-4 animate-spin" />
{{ isSubmitting ? 'Saving...' : 'Save Changes' }}
</Button>
</div>
</form>
</template>