Skip to content

@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

bash
npm install @vibe-labs/design-vue @vibe-labs/design-components

Import 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-modals

Import 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.

PackageComponentsComposables
@vibe-labs/design-vue-avatarsVibeAvatar, VibeAvatarGroupgetInitials
@vibe-labs/design-vue-badgesVibeBadge, VibeBadgeCount, VibeDot
@vibe-labs/design-vue-buttonsVibeButton, VibeButtonGroup
@vibe-labs/design-vue-cardsVibeCard, VibeCardHeader, VibeCardBody, VibeCardFooter, VibeCardMedia
@vibe-labs/design-vue-chartsVibeChartHeatmap, VibeChartLegend, VibeChartLegendGradientuseHeatmapIntensity
@vibe-labs/design-vue-dropdownsVibeDropdown, VibeDropdownTrigger, VibeDropdownMenu, VibeDropdownItem, VibeDropdownGroup, VibeDropdownDivideruseClickOutside, useDropdownKeyboard
@vibe-labs/design-vue-formsVibeFormuseVibeForm, useFormField, createFormValidator, toFormData, dirtyValues + rule builders
@vibe-labs/design-vue-graphsVibeGraphBar, VibeGraphLine, VibeGraphPie, VibeGraphRadar, VibeGraphSparkline, VibeGraphLegend, VibeGraphTooltip, VibeGraphEmptyuseSeriesColors, useGraphDimensions, useTooltip, useRadarGeometry
@vibe-labs/design-vue-hotspotsVibeHotspotuseHotspots, useHotspotsContext
@vibe-labs/design-vue-imagesVibeImage, VibeBgImage, VibePictureuseImageLoad, useLazyLoad, useImageQueue, useRadius
@vibe-labs/design-vue-inputsVibeInput, VibeInputNumber, VibeInputGroup, VibeTextArea, VibeCheckbox, VibeCheckboxGroup, VibeRadio, VibeRadioGroupuseInputField, useAutoResize
@vibe-labs/design-vue-listsVibeList, VibeListItem, VibeListGroup, VibeListDivider, VibeListEmpty
@vibe-labs/design-vue-menusVibeMenu, VibeMenuItem, VibeMenuGroup, VibeMenuDivider, VibeMenuFlyoutuseMenuKeyboard
@vibe-labs/design-vue-modalsVibeModal, VibeModalHeader, VibeModalBody, VibeModalFooteruseModal, useFocusTrap, useScrollLock
@vibe-labs/design-vue-paginationVibePaginationusePagination
@vibe-labs/design-vue-progressVibeProgressBar, VibeProgressRinguseProgress, useProgressTimer
@vibe-labs/design-vue-responsiveVibeResponsiveContainer, VibeResponsiveGrid, VibeResponsiveStackuseContainerBreakpoint
@vibe-labs/design-vue-slidersVibeSlideruseSliderDrag
@vibe-labs/design-vue-spinnersVibeSpinner, VibeSpinnerOverlay, VibeSkeleton
@vibe-labs/design-vue-tabsVibeTabs, VibeTabList, VibeTab, VibeTabPanels, VibeTabPanel
@vibe-labs/design-vue-tablesVibeTableuseTableSort, useTableSelection
@vibe-labs/design-vue-timelineVibeTimeline + 9 sub-componentsuseTimeline, useTimelinePlayback, useTimelineDrag, useTimelineSelection, useTimelineKeyboard, useTimelineZoom
@vibe-labs/design-vue-toastsVibeToast, VibeToastContainertoast (imperative), useToast
@vibe-labs/design-vue-togglesVibeToggle
@vibe-labs/design-vue-uploadsVibeUploadZone, VibeUploadList, VibeUploadItem, VibeUploadIndicatoruseUploadQueue

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
  • vue is 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}.ts

package.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 use prefix: useModal, usePagination, useSliderDrag
  • Return reactive refs or computed values, 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, role where 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.json has version 0.9.0, Vue as peerDependency, and the correct @vibe-labs/design-components-{name} dependency
  • [ ] vite.config.ts externalizes vue and 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 || undefined to 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-vue umbrella 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-components

2. 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

ScenarioUse
Standard application@vibe-labs/design-vue umbrella
Micro-frontend with strict budgetIndividual @vibe-labs/design-vue-* packages
Only need one or two components in a libraryIndividual packages to avoid transitive deps
Building a new Vibe Vue packageIndividual packages as peer/dev dependencies
Prototyping or internal toolsUmbrella — 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()

Vibe