Skip to content

@vibe-labs/design-vue-badges

Vue 3 badge components for the Vibe Design System. Provides label badges, notification counts, and status dots.

Installation

ts
import { VibeBadge, VibeBadgeCount, VibeDot } from "@vibe-labs/design-vue-badges";

Requires the CSS layer from @vibe-labs/design-components-badges.

Components

VibeBadge

Label badge with variant styling, auto-color generation, and optional dismiss button.

Usage

vue
<!-- Basic -->
<VibeBadge label="New" />

<!-- Variants -->
<VibeBadge label="Active" variant="success" />
<VibeBadge label="Warning" variant="warning-subtle" />
<VibeBadge label="Outline" variant="outline" />

<!-- Auto-colored genre pills -->
<VibeBadge label="Electronic" auto-color />
<VibeBadge label="Jazz" auto-color />
<VibeBadge label="Hip Hop" auto-color />

<!-- Custom colors -->
<VibeBadge label="Custom" bg-color="#ff6b6b" />

<!-- Interactive -->
<VibeBadge label="Click me" interactive @click="handleClick" />

<!-- Dismissible -->
<VibeBadge label="Removable" dismissible @dismiss="handleRemove" />

<!-- With icons -->
<VibeBadge label="Tagged">
  <template #left><TagIcon /></template>
</VibeBadge>

<!-- Sizes -->
<VibeBadge label="Small" size="sm" />
<VibeBadge label="Large" size="lg" />

<!-- Shape -->
<VibeBadge label="Square" :pill="false" square />

Props

PropTypeDefaultDescription
labelstringrequiredBadge text content
variantBadgeVariant"accent-subtle"Visual variant
sizeBadgeSize"md"sm · md · lg
pillbooleantrueFull border radius
squarebooleanfalseSmall border radius
interactivebooleanfalseButton role + hover state
dismissiblebooleanfalseShow remove button, emit dismiss
autoColorbooleanfalseDeterministic color from label text
bgColorstringOverride background color
fgColorstringOverride text color (auto-contrasted from bgColor)

Events

EventPayloadDescription
dismissRemove button clicked

Slots

SlotDescription
leftLeading icon
rightTrailing icon (hidden when dismissible)
dismiss-iconCustom dismiss button content (default: ×)

VibeBadgeCount

Notification count badge — works standalone (inline) or anchored to a child element.

Usage

vue
<!-- Inline count -->
<VibeBadgeCount :count="5" />

<!-- Overflow -->
<VibeBadgeCount :count="150" :max="99" />
<!-- Renders: "99+" -->

<!-- Anchored to an icon/button -->
<VibeBadgeCount :count="3">
  <BellIcon />
</VibeBadgeCount>

<!-- Pulse on change -->
<VibeBadgeCount :count="unreadCount" pulse />

<!-- Show zero -->
<VibeBadgeCount :count="0" :hide-zero="false" />

<!-- Custom styling -->
<VibeBadgeCount :count="7" variant="accent" bg-color="#7c5cff" />

Props

PropTypeDefaultDescription
countnumberrequiredThe count to display
maxnumber99Overflow threshold (shows max+)
variantBadgeVariant"danger"Visual variant
sizeBadgeSize"sm"Size preset
hideZerobooleantrueHide badge when count is 0
pulsebooleanfalsePulse animation on count change
bgColorstringOverride background color
fgColorstringOverride text color

Slots

SlotDescription
defaultAnchor element — when provided, count positions as superscript

VibeDot

Minimal status dot indicator.

Usage

vue
<!-- Basic -->
<VibeDot />

<!-- Variants -->
<VibeDot variant="success" aria-label="Online" />
<VibeDot variant="danger" aria-label="Error" />

<!-- Pulsing (live indicator) -->
<VibeDot variant="success" pulse aria-label="Live" />

<!-- Custom color -->
<VibeDot color="#ff6b6b" aria-label="Custom status" />

Props

PropTypeDefaultDescription
variantBadgeVariant"accent"Visual variant
colorstringOverride dot color
pulsebooleanfalsePulsing animation
ariaLabelstringAccessible label (sets role="img", otherwise presentation)

Dependencies

PackagePurpose
@vibe-labs/coreColorFromString for auto-color and contrast
@vibe-labs/design-components-badgesCSS tokens + generated styles

Build

bash
npm run build

Built with Vite + vite-plugin-dts. Outputs ES module with TypeScript declarations.


Usage Guide

Setup

ts
import { VibeBadge, VibeBadgeCount, VibeDot } from "@vibe-labs/design-vue-badges";
import "@vibe-labs/design-components-badges";

VibeBadge

Status and variant badges

vue
<script setup lang="ts">
import { VibeBadge } from "@vibe-labs/design-vue-badges";
</script>

<template>
  <VibeBadge label="Active" variant="success" />
  <VibeBadge label="Pending" variant="warning-subtle" />
  <VibeBadge label="Archived" variant="muted" />
  <VibeBadge label="Error" variant="danger" />
</template>

Auto-colored genre/tag pills

vue
<script setup lang="ts">
import { VibeBadge } from "@vibe-labs/design-vue-badges";

const genres = ["Electronic", "Jazz", "Hip Hop", "Classical", "Rock"];
</script>

<template>
  <!-- Each badge gets a unique deterministic color derived from its label -->
  <div style="display: flex; gap: 6px; flex-wrap: wrap">
    <VibeBadge v-for="genre in genres" :key="genre" :label="genre" auto-color />
  </div>
</template>

Dismissible filter chips

vue
<script setup lang="ts">
import { VibeBadge } from "@vibe-labs/design-vue-badges";
import { ref } from "vue";

const activeFilters = ref(["Electronic", "Live", "2024"]);

function removeFilter(filter: string) {
  activeFilters.value = activeFilters.value.filter((f) => f !== filter);
}
</script>

<template>
  <div style="display: flex; gap: 6px">
    <VibeBadge
      v-for="filter in activeFilters"
      :key="filter"
      :label="filter"
      dismissible
      @dismiss="removeFilter(filter)"
    />
  </div>
</template>

VibeBadgeCount

Notification bell with count

vue
<script setup lang="ts">
import { VibeBadgeCount } from "@vibe-labs/design-vue-badges";
import { ref } from "vue";

const unreadCount = ref(7);
</script>

<template>
  <!-- Count anchors as superscript over the icon -->
  <VibeBadgeCount :count="unreadCount" pulse>
    <BellIcon />
  </VibeBadgeCount>

  <!-- Standalone inline count -->
  <span>Notifications</span>
  <VibeBadgeCount :count="unreadCount" />
</template>

VibeDot

Live status indicator

vue
<script setup lang="ts">
import { VibeDot } from "@vibe-labs/design-vue-badges";

defineProps<{ isLive: boolean }>();
</script>

<template>
  <div style="display: flex; align-items: center; gap: 6px">
    <VibeDot :variant="isLive ? 'success' : 'muted'" :pulse="isLive" :aria-label="isLive ? 'Live' : 'Offline'" />
    <span>{{ isLive ? "Live" : "Offline" }}</span>
  </div>
</template>

Common Patterns

Tag list with overflow

vue
<script setup lang="ts">
import { VibeBadge } from "@vibe-labs/design-vue-badges";
import { VibeOverflowRow } from "@vibe-labs/design-vue-core";

const tags = [
  { id: 1, label: "House" },
  { id: 2, label: "Electronic" },
  { id: 3, label: "Minimal" },
  { id: 4, label: "Deep" },
];
</script>

<template>
  <VibeOverflowRow :items="tags">
    <template #item="{ item }">
      <VibeBadge :label="item.label" auto-color size="sm" />
    </template>
    <template #overflow="{ hiddenCount }">
      <VibeBadge :label="`+${hiddenCount}`" variant="muted" size="sm" />
    </template>
  </VibeOverflowRow>
</template>

Vibe