Appearance
@vibe-labs/design-vue — Developer Reference
Overview
@vibe-labs/design-vue is the umbrella package for all Vibe Vue 3 UI components, composables, types, and constants. It re-exports every individual @vibe-labs/design-vue-* package from a single entry point so consumers do not need to manage multiple package imports.
The umbrella covers:
- 27 Vue component packages
- All associated composables
- Shared TypeScript types and prop interfaces
- Re-exported constants from component-level packages
CSS is not bundled. You must load @vibe-labs/design-components (or individual @vibe-labs/design-components-* packages) separately. See the CSS section below.
Installation
Umbrella package (recommended for most projects)
bash
npm install @vibe-labs/design-vue @vibe-labs/design-componentsImport everything from one place:
ts
import { VibeButton, VibeModal, useModal } from '@vibe-labs/design-vue'Individual packages (tree-shaking / micro-frontends)
Install only what you need:
bash
npm install @vibe-labs/design-vue-buttons @vibe-labs/design-vue-modals
npm install @vibe-labs/design-components-buttons @vibe-labs/design-components-modalsImport directly from the individual package:
ts
import { VibeButton } from '@vibe-labs/design-vue-buttons'
import { VibeModal, useModal } from '@vibe-labs/design-vue-modals'CSS
This package does not bundle any CSS. Class names are generated and shipped by @vibe-labs/design-components. Load styles before your app mounts:
ts
// main.ts — umbrella CSS
import '@vibe-labs/design-components/dist/style.css'Or per-feature if you installed individual packages:
ts
import '@vibe-labs/design-components-buttons/dist/style.css'
import '@vibe-labs/design-components-modals/dist/style.css'Package Table
All 27 Vue packages, their exported components, and composables.
| Package | Components | Composables |
|---|---|---|
@vibe-labs/design-vue-avatars | VibeAvatar, VibeAvatarGroup | getInitials |
@vibe-labs/design-vue-badges | VibeBadge, VibeBadgeCount, VibeDot | — |
@vibe-labs/design-vue-buttons | VibeButton, VibeButtonGroup | — |
@vibe-labs/design-vue-cards | VibeCard, VibeCardHeader, VibeCardBody, VibeCardFooter, VibeCardMedia | — |
@vibe-labs/design-vue-charts | VibeChartHeatmap, VibeChartLegend, VibeChartLegendGradient | useHeatmapIntensity |
@vibe-labs/design-vue-dropdowns | VibeDropdown, VibeDropdownTrigger, VibeDropdownMenu, VibeDropdownItem, VibeDropdownGroup, VibeDropdownDivider | useClickOutside, useDropdownKeyboard |
@vibe-labs/design-vue-forms | VibeForm | useVibeForm, useFormField, createFormValidator, toFormData, dirtyValues + rule builders |
@vibe-labs/design-vue-graphs | VibeGraphBar, VibeGraphLine, VibeGraphPie, VibeGraphRadar, VibeGraphSparkline, VibeGraphLegend, VibeGraphTooltip, VibeGraphEmpty | useSeriesColors, useGraphDimensions, useTooltip, useRadarGeometry |
@vibe-labs/design-vue-hotspots | VibeHotspot | useHotspots, useHotspotsContext |
@vibe-labs/design-vue-images | VibeImage, VibeBgImage, VibePicture | useImageLoad, useLazyLoad, useImageQueue, useRadius |
@vibe-labs/design-vue-inputs | VibeInput, VibeInputNumber, VibeInputGroup, VibeTextArea, VibeCheckbox, VibeCheckboxGroup, VibeRadio, VibeRadioGroup | useInputField, useAutoResize |
@vibe-labs/design-vue-lists | VibeList, VibeListItem, VibeListGroup, VibeListDivider, VibeListEmpty | — |
@vibe-labs/design-vue-menus | VibeMenu, VibeMenuItem, VibeMenuGroup, VibeMenuDivider, VibeMenuFlyout | useMenuKeyboard |
@vibe-labs/design-vue-modals | VibeModal, VibeModalHeader, VibeModalBody, VibeModalFooter | useModal, useFocusTrap, useScrollLock |
@vibe-labs/design-vue-pagination | VibePagination | usePagination |
@vibe-labs/design-vue-progress | VibeProgressBar, VibeProgressRing | useProgress, useProgressTimer |
@vibe-labs/design-vue-responsive | VibeResponsiveContainer, VibeResponsiveGrid, VibeResponsiveStack | useContainerBreakpoint |
@vibe-labs/design-vue-sliders | VibeSlider | useSliderDrag |
@vibe-labs/design-vue-spinners | VibeSpinner, VibeSpinnerOverlay, VibeSkeleton | — |
@vibe-labs/design-vue-tabs | VibeTabs, VibeTabList, VibeTab, VibeTabPanels, VibeTabPanel | — |
@vibe-labs/design-vue-tables | VibeTable | useTableSort, useTableSelection |
@vibe-labs/design-vue-timeline | VibeTimeline + 9 sub-components | useTimeline, useTimelinePlayback, useTimelineDrag, useTimelineSelection, useTimelineKeyboard, useTimelineZoom |
@vibe-labs/design-vue-toasts | VibeToast, VibeToastContainer | toast (imperative), useToast |
@vibe-labs/design-vue-toggles | VibeToggle | — |
@vibe-labs/design-vue-uploads | VibeUploadZone, VibeUploadList, VibeUploadItem, VibeUploadIndicator | useUploadQueue |
Build System
All Vue packages use Vite in library mode with vite-plugin-dts for TypeScript declaration generation.
- Output format: ES module (
es) - All
@vibe-labs/*packages are externalized vueis externalized as a peer dependency- Declaration files (
.d.ts) are emitted alongside the bundle
Building a New Vue Package
Package anatomy
@vibe-labs/design-vue-{name}/
package.json
tsconfig.json
vite.config.ts
src/
index.ts ← barrel export
types.ts ← prop interfaces + re-exported style types
components/
Vibe{Name}.vue
composables/
use{Name}.tspackage.json template
json
{
"name": "@vibe-labs/design-vue-{name}",
"version": "0.9.0",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
}
},
"peerDependencies": {
"vue": "^3.4.0"
},
"dependencies": {
"@vibe-labs/core": "workspace:*",
"@vibe-labs/design-components-{name}": "workspace:*"
},
"devDependencies": {
"vue": "^3.4.0"
},
"scripts": {
"build": "vite build && vue-tsc --declaration --emitDeclarationOnly"
}
}vite.config.ts template
ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import dts from 'vite-plugin-dts'
export default defineConfig({
plugins: [
vue(),
dts({ insertTypesEntry: true }),
],
build: {
lib: {
entry: 'src/index.ts',
formats: ['es'],
fileName: 'index',
},
rollupOptions: {
external: ['vue', /^@vibe\//],
output: {
globals: { vue: 'Vue' },
},
},
},
})tsconfig.json template
json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2020", "DOM"],
"strict": true,
"skipLibCheck": true,
"paths": {
"@vibe-labs/core": ["../../core/src/index.ts"],
"@vibe-labs/design-components-{name}": ["../design-components-{name}/src/index.ts"]
}
},
"include": ["src"]
}src/types.ts pattern
Re-export component-level style types from @vibe-labs/design-components-{name}, then define Vue prop interfaces on top:
ts
// Re-export style types from the CSS/component layer
export type { {Name}Variant, {Name}Size } from '@vibe-labs/design-components-{name}'
// Vue prop interfaces
export interface Vibe{Name}Props {
variant?: {Name}Variant
size?: {Name}Size
disabled?: boolean
// ... additional Vue-level props
}SFC authoring conventions
Class names come from the design-components package. Do not write <style> blocks in Vue SFCs — class names are provided by the CSS layer.
Enum props use data-variant and data-size HTML attributes:
vue
<template>
<button
v-bind="$attrs"
:class="classes"
:data-variant="variant"
:data-size="size"
:data-loading="loading || undefined"
:disabled="disabled || undefined"
>
<slot />
</button>
</template>Boolean data attributes use :data-flag="flag || undefined". Passing undefined removes the attribute from the DOM entirely, avoiding data-flag="false" pollution.
Attribute inheritance must be disabled and manually applied to the root element:
vue
<script setup lang="ts">
defineOptions({ inheritAttrs: false })
</script>
<template>
<div v-bind="$attrs" :class="rootClass">
<slot />
</div>
</template>Optional props should always use withDefaults:
vue
<script setup lang="ts">
import type { Vibe{Name}Props } from '../types'
const props = withDefaults(defineProps<Vibe{Name}Props>(), {
variant: 'primary',
size: 'md',
disabled: false,
})
</script>Prefer semantic HTML and ARIA over custom data attributes for conveying state. Use aria-disabled, aria-expanded, role, aria-label, etc., rather than data attributes for accessibility-relevant information.
Barrel (src/index.ts)
Export components, then re-export all types and constants:
ts
// Components
export { default as Vibe{Name} } from './components/Vibe{Name}.vue'
// Types
export type { Vibe{Name}Props, {Name}Variant, {Name}Size } from './types'
// Constants (re-export from design-components layer)
export { {NAME}_VARIANTS, {NAME}_SIZES } from '@vibe-labs/design-components-{name}'Provide / Inject Pattern
Compound components (tabs, dropdown, form, menu, list) share state via Vue's provide/inject rather than prop drilling or a global store.
ts
// types.ts
export interface TabsContext {
activeTab: Ref<string>
setActiveTab: (id: string) => void
}
export const TABS_INJECTION_KEY: InjectionKey<TabsContext> = Symbol('VibeTabs')vue
<!-- VibeTabs.vue (parent) -->
<script setup lang="ts">
import { provide, ref } from 'vue'
import { TABS_INJECTION_KEY } from '../types'
const activeTab = ref(props.modelValue ?? '')
provide(TABS_INJECTION_KEY, {
activeTab,
setActiveTab: (id) => { activeTab.value = id },
})
</script>vue
<!-- VibeTab.vue (child) -->
<script setup lang="ts">
import { inject } from 'vue'
import { TABS_INJECTION_KEY } from '../types'
const tabs = inject(TABS_INJECTION_KEY)
</script>Composable Conventions
- Name with
useprefix:useModal,usePagination,useSliderDrag - Return reactive
refs orcomputedvalues, not raw values - Register cleanup in
onUnmounted(remove event listeners, cancel timers, abort fetch) - Accept options as a single typed options object for forward compatibility
- Do not call composables conditionally
ts
// Example pattern
export function useProgressTimer(options: ProgressTimerOptions) {
const elapsed = ref(0)
let timer: ReturnType<typeof setInterval> | null = null
function start() {
timer = setInterval(() => { elapsed.value += options.step ?? 100 }, options.step ?? 100)
}
function stop() {
if (timer !== null) clearInterval(timer)
}
onUnmounted(stop)
return { elapsed: readonly(elapsed), start, stop }
}Accessibility Baseline
Every component must meet these requirements:
- Semantic HTML: use
<button>,<nav>,<ul>,<dialog>, etc., not<div>everywhere - ARIA attributes:
aria-label/aria-labelledby,aria-expanded,aria-selected,aria-disabled,rolewhere native semantics are insufficient - Keyboard navigation: interactive components must be fully operable via keyboard
- Focus management: modals and dropdowns must trap / restore focus
- No CSS-only state: do not rely solely on
data-*attributes for state that screen readers need to understand
Checklist for New Vue Packages
- [ ]
package.jsonhas version0.9.0, Vue aspeerDependency, and the correct@vibe-labs/design-components-{name}dependency - [ ]
vite.config.tsexternalizesvueand all/^@vibe\// - [ ] No
<style>blocks in SFCs - [ ]
defineOptions({ inheritAttrs: false })+v-bind="$attrs"on root element - [ ] All optional props use
withDefaults - [ ] Boolean
data-*attributes use|| undefinedto avoid false-valued attributes - [ ] Compound components use provide/inject with a typed
InjectionKey - [ ] Composables clean up in
onUnmounted - [ ] Barrel (
src/index.ts) exports components, types, and constants - [ ] Semantic HTML and ARIA requirements met
- [ ] Package added to
@vibe-labs/design-vueumbrella re-exports
@vibe-labs/design-vue — Usage Guide
AI-optimized reference. Each section is self-contained and copy-paste ready.
Quick Start
1. Install
bash
npm install @vibe-labs/design-vue @vibe-labs/design-components2. Load CSS
CSS is not bundled in @vibe-labs/design-vue. You must import it separately before your app mounts:
ts
// main.ts
import { createApp } from 'vue'
import '@vibe-labs/design-components/dist/style.css'
import App from './App.vue'
createApp(App).mount('#app')3. Import components
ts
import {
VibeButton,
VibeModal,
VibeInput,
useModal,
} from '@vibe-labs/design-vue'Component Usage Patterns
VibeButton
vue
<template>
<!-- Variants -->
<VibeButton variant="primary">Save</VibeButton>
<VibeButton variant="secondary">Cancel</VibeButton>
<VibeButton variant="ghost">Learn more</VibeButton>
<VibeButton variant="danger">Delete</VibeButton>
<!-- Sizes -->
<VibeButton size="sm">Small</VibeButton>
<VibeButton size="md">Medium</VibeButton>
<VibeButton size="lg">Large</VibeButton>
<!-- Loading state -->
<VibeButton :loading="isSaving" variant="primary">
{{ isSaving ? 'Saving…' : 'Save' }}
</VibeButton>
<!-- Disabled -->
<VibeButton :disabled="!isValid" variant="primary">Submit</VibeButton>
<!-- Custom color (cascades --color-accent) -->
<VibeButton color="#e85d04">Custom</VibeButton>
<!-- Polymorphic: render as <a> -->
<VibeButton as="a" href="/docs" target="_blank">View docs</VibeButton>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { VibeButton } from '@vibe-labs/design-vue'
const isSaving = ref(false)
const isValid = ref(true)
</script>VibeBadge
vue
<template>
<!-- Variants -->
<VibeBadge variant="success">Active</VibeBadge>
<VibeBadge variant="warning">Pending</VibeBadge>
<VibeBadge variant="danger">Error</VibeBadge>
<VibeBadge variant="neutral">Draft</VibeBadge>
<!-- Auto-color from value string -->
<VibeBadge :autoColor="true">marine</VibeBadge>
<!-- Dismissible -->
<VibeBadge
v-for="tag in tags"
:key="tag"
dismissible
@dismiss="removeTag(tag)"
>
{{ tag }}
</VibeBadge>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { VibeBadge } from '@vibe-labs/design-vue'
const tags = ref(['ocean', 'reef', 'survey'])
function removeTag(tag: string) {
tags.value = tags.value.filter(t => t !== tag)
}
</script>VibeCard with sections
vue
<template>
<VibeCard>
<VibeCardMedia>
<img src="/survey-photo.jpg" alt="Survey site aerial view" />
</VibeCardMedia>
<VibeCardHeader>
<h3>Reef Survey — Site A</h3>
</VibeCardHeader>
<VibeCardBody>
<p>Coral coverage recorded at 68% across 12 transects.</p>
</VibeCardBody>
<VibeCardFooter>
<VibeButton variant="primary" size="sm">View Report</VibeButton>
<VibeButton variant="ghost" size="sm">Share</VibeButton>
</VibeCardFooter>
</VibeCard>
</template>
<script setup lang="ts">
import { VibeCard, VibeCardHeader, VibeCardBody, VibeCardFooter, VibeCardMedia, VibeButton } from '@vibe-labs/design-vue'
</script>VibeInput with label and validation
vue
<template>
<VibeInput
v-model="email"
label="Email address"
type="email"
placeholder="you@example.com"
:error="emailError"
:required="true"
/>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { VibeInput } from '@vibe-labs/design-vue'
const email = ref('')
const emailError = computed(() => {
if (!email.value) return 'Email is required'
if (!email.value.includes('@')) return 'Enter a valid email address'
return ''
})
</script>VibeModal with useModal
vue
<template>
<VibeButton variant="primary" @click="modal.open()">
Open Modal
</VibeButton>
<VibeModal :open="modal.isOpen.value" @close="modal.close()">
<VibeModalHeader>Confirm deletion</VibeModalHeader>
<VibeModalBody>
<p>This action cannot be undone. Are you sure you want to delete this survey?</p>
</VibeModalBody>
<VibeModalFooter>
<VibeButton variant="ghost" @click="modal.close()">Cancel</VibeButton>
<VibeButton variant="danger" @click="handleDelete">Delete</VibeButton>
</VibeModalFooter>
</VibeModal>
</template>
<script setup lang="ts">
import {
VibeButton,
VibeModal,
VibeModalHeader,
VibeModalBody,
VibeModalFooter,
useModal,
} from '@vibe-labs/design-vue'
const modal = useModal()
function handleDelete() {
// perform delete
modal.close()
}
</script>VibeTable with useTableSort
vue
<template>
<VibeTable
:columns="columns"
:rows="sortedRows"
:sort="sort"
@sort="setSort"
/>
</template>
<script setup lang="ts">
import { VibeTable, useTableSort } from '@vibe-labs/design-vue'
const rows = [
{ id: 1, site: 'Site A', coverage: 68, date: '2025-03-01' },
{ id: 2, site: 'Site B', coverage: 42, date: '2025-03-04' },
{ id: 3, site: 'Site C', coverage: 81, date: '2025-02-28' },
]
const columns = [
{ key: 'site', label: 'Site', sortable: true },
{ key: 'coverage', label: 'Coverage (%)', sortable: true },
{ key: 'date', label: 'Survey Date', sortable: true },
]
const { sort, sortedRows, setSort } = useTableSort(rows, { key: 'date', direction: 'desc' })
</script>VibeToast with toast() imperative API
vue
<template>
<!-- Mount once at app root -->
<VibeToastContainer />
<VibeButton variant="primary" @click="handleSave">Save changes</VibeButton>
</template>
<script setup lang="ts">
import { VibeToastContainer, VibeButton, toast } from '@vibe-labs/design-vue'
async function handleSave() {
try {
await saveData()
toast.success('Changes saved successfully.')
} catch (err) {
toast.error('Save failed. Please try again.')
}
}
</script>All toast variants:
ts
toast.success('Done!')
toast.error('Something went wrong.')
toast.warning('Low disk space.')
toast.info('New version available.')
toast('Custom message', { duration: 8000, dismissible: true })VibeForm with useVibeForm
vue
<template>
<VibeForm :form="form" @submit="handleSubmit">
<VibeInput
v-model="form.fields.name.value"
label="Full name"
:error="form.fields.name.error"
/>
<VibeInput
v-model="form.fields.email.value"
label="Email"
type="email"
:error="form.fields.email.error"
/>
<VibeButton
type="submit"
variant="primary"
:loading="form.isSubmitting.value"
:disabled="!form.isValid.value"
>
Submit
</VibeButton>
</VibeForm>
</template>
<script setup lang="ts">
import {
VibeForm,
VibeInput,
VibeButton,
useVibeForm,
createFormValidator,
} from '@vibe-labs/design-vue'
const form = useVibeForm({
name: {
initial: '',
rules: [createFormValidator.required('Name is required')],
},
email: {
initial: '',
rules: [
createFormValidator.required('Email is required'),
createFormValidator.email('Enter a valid email'),
],
},
})
async function handleSubmit() {
if (!form.validate()) return
await submitToApi(form.values())
}
</script>VibePagination with usePagination
vue
<template>
<ul>
<li v-for="item in pageItems" :key="item.id">{{ item.name }}</li>
</ul>
<VibePagination
:current="pagination.currentPage.value"
:total="pagination.totalPages.value"
@change="pagination.goTo"
/>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { VibePagination, usePagination } from '@vibe-labs/design-vue'
const allItems = Array.from({ length: 87 }, (_, i) => ({ id: i + 1, name: `Survey ${i + 1}` }))
const pagination = usePagination({ total: allItems.length, pageSize: 10 })
const pageItems = computed(() =>
allItems.slice(pagination.offset.value, pagination.offset.value + 10)
)
</script>Loading CSS
@vibe-labs/design-vue ships no CSS. Class names are defined in @vibe-labs/design-components. You must load styles separately.
Option A — Umbrella CSS (simplest)
ts
import '@vibe-labs/design-components/dist/style.css'Option B — Individual CSS packages (smaller bundles)
ts
import '@vibe-labs/design-components-buttons/dist/style.css'
import '@vibe-labs/design-components-inputs/dist/style.css'
import '@vibe-labs/design-components-modals/dist/style.css'Match each @vibe-labs/design-vue-* package you use with its corresponding @vibe-labs/design-components-* CSS package.
Tree-Shaking
Modern bundlers (Vite, webpack 5+) tree-shake the umbrella automatically. To guarantee the smallest possible bundle or to avoid loading unneeded packages in a micro-frontend, import directly from individual packages:
ts
// Instead of:
import { VibeButton } from '@vibe-labs/design-vue'
// Import from the leaf package:
import { VibeButton } from '@vibe-labs/design-vue-buttons'Custom Color via color Prop
Passing a color prop to most components sets the --color-accent CSS custom property on the root element. Child elements that reference --color-accent inherit the override automatically.
vue
<VibeButton color="#0077b6">Ocean blue</VibeButton>
<VibeProgressBar :value="72" color="#e9c46a" />
<VibeBadge color="#2a9d8f">Custom</VibeBadge>The value is applied as an inline style: style="--color-accent: #0077b6". This does not affect sibling or parent elements.
Umbrella vs Individual Packages
| Scenario | Use |
|---|---|
| Standard application | @vibe-labs/design-vue umbrella |
| Micro-frontend with strict budget | Individual @vibe-labs/design-vue-* packages |
| Only need one or two components in a library | Individual packages to avoid transitive deps |
| Building a new Vibe Vue package | Individual packages as peer/dev dependencies |
| Prototyping or internal tools | Umbrella — fastest to set up |
The umbrella is the default choice. Switch to individual packages only when bundle size or dependency isolation is a hard constraint.
Package Contents
@vibe-labs/design-vue-avatars
Import: import { VibeAvatar, VibeAvatarGroup, getInitials } from "@vibe-labs/design-vue-avatars";CSS required: @import "@vibe-labs/design-components-avatars";
Components
VibeAvatar · VibeAvatarGroup
Key Props
name (required) · src · thumbSrc · size (xs/sm/md/lg/xl) · status (online/offline/busy/away) · bgColor · fgColor · ring · clickable · loading
Utilities
getInitials(name, max?)
@vibe-labs/design-vue-badges
Import: import { VibeBadge, VibeBadgeCount, VibeDot } from "@vibe-labs/design-vue-badges";CSS required: @import "@vibe-labs/design-components-badges";
Components
VibeBadge · VibeBadgeCount · VibeDot
Key Props
VibeBadge: label (required) · variant · size (sm/md/lg) · pill · interactive · dismissible · autoColor · bgColor · fgColorVibeBadgeCount: count (required) · max · hideZero · pulse · variantVibeDot: variant · color · pulse · ariaLabel
@vibe-labs/design-vue-buttons
Import: import { VibeButton, VibeButtonGroup } from "@vibe-labs/design-vue-buttons";CSS required: @import "@vibe-labs/design-components-buttons";
Components
VibeButton · VibeButtonGroup
Key Props
VibeButton: variant (primary/secondary/ghost/danger/link) · size (sm/md/lg) · shape (default/circle) · loading · full · icon · disabled · color · as · typeVibeButtonGroup: role (group/toolbar) · label
@vibe-labs/design-vue-cards
Import: import { VibeCard, VibeCardHeader, VibeCardBody, VibeCardFooter, VibeCardMedia } from "@vibe-labs/design-vue-cards";CSS required: @import "@vibe-labs/design-components-cards";
Components
VibeCard · VibeCardHeader · VibeCardBody · VibeCardFooter · VibeCardMedia
Key Props
VibeCard: variant (default/elevated/outlined/ghost/gradient/gradient-subtle/gradient-elevated) · size (sm/md/lg) · interactive · horizontal · seamless · flush · as · hrefVibeCardMedia: position (top/bottom)
@vibe-labs/design-vue-charts
Import: import { VibeChartHeatmap, VibeChartLegend, VibeChartLegendGradient, useHeatmapIntensity } from "@vibe-labs/design-vue-charts";CSS required: @import "@vibe-labs/design-components-charts";
Components
VibeChartHeatmap · VibeChartLegend · VibeChartLegendGradient
Key Props
VibeChartHeatmap: rows (required) · xLabels · yLabels · min · max · size (sm/md/lg) · colorScale · rounded · seamless · interactive · ariaLabelVibeChartLegend: items (required) · layout (horizontal/vertical) VibeChartLegendGradient: minLabel · maxLabel
Composables
useHeatmapIntensity()
@vibe-labs/design-vue-core
Import: import { VibePanel, VibeLink, VibeLabel, VibeDivider, VibeHidden, VibeOverflowRow } from "@vibe-labs/design-vue-core";CSS required: @import "@vibe-labs/design-components-core";
Components
VibePanel · VibeLink · VibeLabel · VibeDivider · VibeHidden · VibeOverflowRow
Key Props
VibePanel: variant (default/outlined/raised/ghost) · size (sm/md/lg/xl) · flush · as · sectionVibeLink: href · to · variant (accent/muted/inherit) · external · active · disabled · asVibeLabel: for · size (sm/md/lg) · required · disabledVibeDivider: orientation (horizontal/vertical) · ariaLabelVibeOverflowRow: items (requires id) · gapVibeHidden: focusable · as
@vibe-labs/design-vue-dropdowns
Import: import { VibeDropdown, VibeDropdownTrigger, VibeDropdownMenu, VibeDropdownItem, VibeDropdownGroup, VibeDropdownDivider } from "@vibe-labs/design-vue-dropdowns";CSS required: @import "@vibe-labs/design-components-dropdowns";
Components
VibeDropdown · VibeDropdownTrigger · VibeDropdownMenu · VibeDropdownItem · VibeDropdownGroup · VibeDropdownDivider
Key Props
VibeDropdown: open (v-model) · closeOnSelect · closeOnClickOutside · closeOnEscapeVibeDropdownMenu: align · fullVibeDropdownItem: value · variant · href · disabled · selected
Composables
useClickOutside() · useMenuKeyboard()
@vibe-labs/design-vue-forms
Import: import { VibeForm, useVibeForm, useFormField, required, email, minLength, maxLength, pattern, url, min, max, matches, custom, createFormValidator, toFormData, dirtyValues } from "@vibe-labs/design-vue-forms";CSS required: none (pure logic package)
Components
VibeForm
Key Props
VibeForm: initial-values (required) · validate · validate-on (change/blur/submit) · no-form-error · id · autocomplete
Composables
useVibeForm() · useFormField()
Validation Rules
required() · email() · minLength() · maxLength() · pattern() · url() · min() · max() · matches() · custom() · createFormValidator()
Utilities
toFormData() · dirtyValues()
@vibe-labs/design-vue-graphs
Import: import { VibeGraphBar, VibeGraphLine, VibeGraphPie, VibeGraphSparkline, VibeGraphRadar, VibeGraphLegend, VibeGraphTooltip, VibeGraphEmpty } from "@vibe-labs/design-vue-graphs";CSS required: @import "@vibe-labs/design-components-graphs";
Components
VibeGraphBar · VibeGraphLine · VibeGraphPie · VibeGraphSparkline · VibeGraphRadar · VibeGraphLegend · VibeGraphTooltip · VibeGraphEmpty
Key Props
All charts: width · height · ratio · legend · legendPosition · tooltip · animate · ariaLabelVibeGraphBar: series · horizontal · stacked · barRadiusVibeGraphLine: series · curve · points · areaVibeGraphPie: data · innerRadius · labelsVibeGraphRadar: axes · series · gridStyle · gridLevels · max · fillVibeGraphSparkline: data · color · area · showExtremes
Composables
useSeriesColors() · resolveSeriesColor() · useGraphDimensions() · useTooltip() · useRadarGeometry()
@vibe-labs/design-vue-hotspots
Import: import { VibeHotspot, useHotspots, useHotspotsContext } from "@vibe-labs/design-vue-hotspots";CSS required: none (purely behavioural package)
Components
VibeHotspot
Key Props
VibeHotspot: id (required) · meta · tag
Composables
useHotspots() · useHotspotsContext()
@vibe-labs/design-vue-images
Import: import { VibeImage, VibeBgImage, VibePicture, useImageLoad, useLazyLoad, useImageQueue, useRadius } from "@vibe-labs/design-vue-images";CSS required: none (styles are inline/scoped)
Components
VibeImage · VibeBgImage · VibePicture
Key Props
VibeImage: src · thumbSrc · alt · srcset · sizes · width · height · fit · loading · crossfade · duration · radius · asVibeBgImage: src · thumbSrc · fit · position · fixed · overlay · ariaLabelVibePicture: all VibeImage props (except as, srcset, sizes) · sources
Composables
useImageLoad() · useLazyLoad() · useImageQueue() · useRadius()
@vibe-labs/design-vue-inputs
Import: import { VibeInput, VibeInputNumber, VibeInputGroup, VibeTextArea, VibeCheckbox, VibeCheckboxGroup, VibeRadio, VibeRadioGroup } from "@vibe-labs/design-vue-inputs";CSS required: @import "@vibe-labs/design-components-inputs";
Components
VibeInput · VibeInputNumber · VibeInputGroup · VibeTextArea · VibeCheckbox · VibeCheckboxGroup · VibeRadio · VibeRadioGroup
Key Props
VibeInput: modelValue · type · size (sm/md/lg) · label · error · success · required · rules · validateOn · debounce · showCount · maxlengthVibeInputNumber: modelValue · min · max · step · precision · controls · nullableVibeInputGroup: label · direction (vertical/horizontal) · seamless · errorVibeTextArea: modelValue · rows · autoResize · maxRows · showCount · resizableVibeCheckbox: modelValue · value · label · indeterminateVibeRadio / VibeRadioGroup: modelValue · value · name · horizontal
Composables
useInputField() · useAutoResize()
@vibe-labs/design-vue-lists
Import: import { VibeList, VibeListItem, VibeListGroup, VibeListDivider, VibeListEmpty } from "@vibe-labs/design-vue-lists";CSS required: @import "@vibe-labs/design-components-lists";
Components
VibeList · VibeListItem · VibeListGroup · VibeListDivider · VibeListEmpty
Key Props
VibeList: variant · size (sm/md/lg) · divided · striped · hoverable · interactive · flush · reorderable · selectionMode (none/single/multi) · selected (v-model) VibeListItem: value · label · description · disabledVibeListGroup: labelVibeListEmpty: message
@vibe-labs/design-vue-menus
Import: import { VibeMenu, VibeMenuItem, VibeMenuGroup, VibeMenuDivider, VibeMenuFlyout } from "@vibe-labs/design-vue-menus";CSS required: @import "@vibe-labs/design-components-menus";
Components
VibeMenu · VibeMenuItem · VibeMenuGroup · VibeMenuFlyout · VibeMenuDivider
Key Props
nav · horizontal · compact · label · active · disabled · href · to · as · chevron · expanded · trail · collapsible · trigger · align · open
Composables
useMenuKeyboard()
@vibe-labs/design-vue-modals
Import: import { VibeModal, VibeModalHeader, VibeModalBody, VibeModalFooter, useModal, useFocusTrap, useScrollLock } from "@vibe-labs/design-vue-modals";CSS required: @import "@vibe-labs/design-components-modals";
Components
VibeModal · VibeModalHeader · VibeModalBody · VibeModalFooter
Key Props
VibeModal: open (v-model) · size (sm/md/lg/xl/full) · variant · drawer · drawerSide (left/right) · noBackdrop · beforeClose · centered · seamless · closeOnBackdrop · closeOnEscape · trapFocus · lockScroll · teleport · noClose · initialFocusVibeModalHeader: srOnlyVibeModalFooter: split
Composables
useModal() · useFocusTrap() · useScrollLock()
@vibe-labs/design-vue-pagination
Import: import { VibePagination } from "@vibe-labs/design-vue-pagination";CSS required: @import "@vibe-labs/design-components-pagination";
Components
VibePagination
Key Props
page · totalPages · siblings · showPrevNext · prevLabel · nextLabel · disabled · ariaLabel
Composables
usePagination()
@vibe-labs/design-vue-progress
Import: import { VibeProgressBar, VibeProgressRing } from "@vibe-labs/design-vue-progress";CSS required: @import "@vibe-labs/design-components-progress";
Components
VibeProgressBar · VibeProgressRing
Key Props
value · min · max · size · variant · color · autoThresholds · label · formatLabel · indeterminate · striped · animated · shimmer · strokeWidth · showLabel
Composables
useProgress() · useProgressTimer()
@vibe-labs/design-vue-responsive
Import: import { VibeResponsiveContainer, VibeResponsiveGrid, VibeResponsiveStack, useContainerBreakpoint } from "@vibe-labs/design-vue-responsive";CSS required: @import "@vibe-labs/design-components-responsive";
Components
VibeResponsiveContainer · VibeResponsiveGrid · VibeResponsiveStack
Key Props
tag · type · name · cols · colsXs · colsSm · colsMd · colsLg · colsXl · cols2xl · breakpoint
Composables
useContainerBreakpoint()
@vibe-labs/design-vue-sliders
Import: import { VibeSlider } from "@vibe-labs/design-vue-sliders";CSS required: @import "@vibe-labs/design-components-sliders";
Components
VibeSlider
Key Props
modelValue · min · max · step · range · size · orientation · thumbShape · color · tooltip · marks · formatValue · disabled
Composables
useSliderDrag()
@vibe-labs/design-vue-spinners
Import: import { VibeSpinner, VibeSpinnerOverlay, VibeSkeleton } from "@vibe-labs/design-vue-spinners";CSS required: @import "@vibe-labs/design-components-spinners";
Components
VibeSpinner · VibeSpinnerOverlay · VibeSkeleton
Key Props
size · color · label · stacked · ariaLabel · visible · shape · lines · width · height · static
@vibe-labs/design-vue-tables
Import: import { VibeTable, useTableSort, useTableSelection } from "@vibe-labs/design-vue-tables";CSS required: @import "@vibe-labs/design-components-tables";
Components
VibeTable
Key Props
columns · items · rowKey · sort · variant · size · striped · hoverable · interactive · fixedHeader · emptyText · rowSelected · rowDisabled
Composables
useTableSort() · useTableSelection()
@vibe-labs/design-vue-tabs
Import: import { VibeTabs, VibeTabList, VibeTab, VibeTabPanels, VibeTabPanel } from "@vibe-labs/design-vue-tabs";CSS required: @import "@vibe-labs/design-components-tabs";
Components
VibeTabs · VibeTabList · VibeTab · VibeTabPanels · VibeTabPanel
Key Props
modelValue · defaultValue · mountStrategy · variant · scrollable · full · name · disabled · badge
@vibe-labs/design-vue-timeline
Import: import { VibeTimeline, VibeTimelineRuler, VibeTimelineTrack, VibeTimelineTrackGroup, VibeTimelineBlock, VibeTimelineMarker, VibeTimelinePlayhead, VibeTimelineGrid, VibeTimelineWaveform, VibeTimelineSelection } from "@vibe-labs/design-vue-timeline";CSS required: @import "@vibe-labs/design-components-timeline";
Components
VibeTimeline · VibeTimelineRuler · VibeTimelineTrackGroup · VibeTimelineTrack · VibeTimelineBlock · VibeTimelineMarker · VibeTimelinePlayhead · VibeTimelineGrid · VibeTimelineWaveform · VibeTimelineSelection
Key Props
duration · currentTime · playing · density · snap · snapping · looping · pixelsPerUnit · start · label · variant · selected · resizable · draggable · kind · muted · solo · locked
Composables
useTimeline() · useTimelinePlayback() · useTimelineDrag() · useTimelineSelection() · useTimelineKeyboard() · useTimelineZoom()
@vibe-labs/design-vue-toasts
Import: import { toast, VibeToastContainer, useToast } from "@vibe-labs/design-vue-toasts";CSS required: @import "@vibe-labs/design-components-toasts";
Components
VibeToastContainer · VibeToast
Key Props
position · limit · mode · pauseOnHover · defaultDuration
Composables
useToast()
Imperative API
toast() · toast.success() · toast.warning() · toast.danger() · toast.info() · toast.promise() · toast.dismiss() · toast.dismissAll() · toast.update()
@vibe-labs/design-vue-toggles
Import: import { VibeToggle } from "@vibe-labs/design-vue-toggles";CSS required: @import "@vibe-labs/design-components-toggles";
Components
VibeToggle
Key Props
modelValue · size · disabled · label · labelPosition · name · value · required · ariaLabel · ariaLabelledby · ariaDescribedby
@vibe-labs/design-vue-uploads
Import: import { VibeUploadZone, VibeUploadList, VibeUploadItem, VibeUploadIndicator, useUploadQueue } from "@vibe-labs/design-vue-uploads";CSS required: @import "@vibe-labs/design-components-uploads";
Components
VibeUploadZone · VibeUploadList · VibeUploadItem · VibeUploadIndicator
Key Props
accept · multiple · disabled · compact · directory · file · showPreview · removable · progress · active · total · complete · error
Composables
useUploadQueue()